Why is std::vector so much slower then array pointer [closed] - c++

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
Im creating a Opengl font batch draw.
I want to know why my std::vector is so much slower then using a array pointer.
I have tried adding vector reserve and everything i can think of.
My FPS drops just over half when using vectors.
Vectors seem easier to manage and look nicer in code, but im really stuck on this.
Not sure if its something simple that i have missed?
Or is it better to just use array pointers?
#ifdef USE_VECTORS
std::vector<Vertex> m_vertices;
#else
Vertex *m_pVertex;
Vertex m_vertices[MAX_VERTICES];
#endif
drawing char function
void GLFont::drawChar(char c, int x, int y)
{
// 1------4
// | | 1 = (x, y)
// | | 2 = (x, y + charHeight)
// | | 3 = (x + charWidth, y + charHeight)
// | | 4 = (x + charWidth, y)
// | |
// | |
// 2------3
//
const Glyph &glyph = getChar(c);
int charWidth = glyph.width;
int charHeight = m_charHeight;
#ifdef USE_VECTORS
Vertex vert[] = {
x, y,
glyph.upperLeft[0], glyph.upperLeft[1],
m_color[0], m_color[1], m_color[2], m_color[3],
x, y + charHeight,
glyph.lowerLeft[0], glyph.lowerLeft[1],
m_color[0], m_color[1], m_color[2], m_color[3],
x + charWidth, y + charHeight,
glyph.lowerRight[0], glyph.lowerRight[1],
m_color[0], m_color[1], m_color[2], m_color[3],
x + charWidth, y,
glyph.upperRight[0], glyph.upperRight[1],
m_color[0], m_color[1], m_color[2], m_color[3]
};
//unsigned dataArraySize = sizeof(vert) / sizeof(Vertex);
m_vertices.insert(m_vertices.end(), &vert[0], &vert[4]);
++m_numCharsToDraw;
#else
//1
m_pVertex->x = x;
m_pVertex->y = y;
m_pVertex->s = glyph.upperLeft[0];
m_pVertex->t = glyph.upperLeft[1];
m_pVertex->r = m_color[0];
m_pVertex->g = m_color[1];
m_pVertex->b = m_color[2];
m_pVertex->a = m_color[3];
++m_pVertex;
// 2
m_pVertex->x = x;
m_pVertex->y = y + charHeight;
m_pVertex->s = glyph.lowerLeft[0];
m_pVertex->t = glyph.lowerLeft[1];
m_pVertex->r = m_color[0];
m_pVertex->g = m_color[1];
m_pVertex->b = m_color[2];
m_pVertex->a = m_color[3];
++m_pVertex;
// 3
m_pVertex->x = x + charWidth;
m_pVertex->y = y + charHeight;
m_pVertex->s = glyph.lowerRight[0];
m_pVertex->t = glyph.lowerRight[1];
m_pVertex->r = m_color[0];
m_pVertex->g = m_color[1];
m_pVertex->b = m_color[2];
m_pVertex->a = m_color[3];
++m_pVertex;
// 4
m_pVertex->x = x + charWidth;
m_pVertex->y = y;
m_pVertex->s = glyph.upperRight[0];
m_pVertex->t = glyph.upperRight[1];
m_pVertex->r = m_color[0];
m_pVertex->g = m_color[1];
m_pVertex->b = m_color[2];
m_pVertex->a = m_color[3];
++m_pVertex;
if (++m_numCharsToDraw == MAX_CHARS_PER_BATCH)
{
drawTextEnd();
drawBatchOfChars();
drawTextBegin();
}
#endif
}
void GLFont::drawBatchOfChars()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
#ifdef USE_VECTORS
glVertexPointer(2, GL_INT, sizeof(Vertex), &m_vertices[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &m_vertices[0].s);
glColorPointer(4, GL_FLOAT, sizeof(Vertex), &m_vertices[0].r);
#else
glVertexPointer(2, GL_INT, sizeof(Vertex), &m_vertices->x);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &m_vertices->s);
glColorPointer(4, GL_FLOAT, sizeof(Vertex), &m_vertices->r);
#endif
glDrawArrays(GL_QUADS, 0, m_numCharsToDraw * 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}

You are comparing apples to oranges:
Containers contain pointers themselves, reducing locality of data.
Containers need to reallocate storage when changing size.
Microsoft's Visual Studio enables additional diagnostics in their standardlibrary containers. For example, accessing via vec[123] causes undefined behaviour per standard if the index is out of range. This allows implementing this as simple indexing via the pointer to the array's payload. With additional diagnostics, the index is validated, which is just a small comparison and a branch, but in tight loops it makes a difference.
That said, your approach to prove something is flawed. You'd first have to implement equivalent code that is reduced as far as possible (in the spirit of an MCVE). Hooking an OpenGL backend onto it isn't going to make things reproducible.

The main reason for you to see a large performance difference is Debug mode.
In Debug mode MSVC by default inlines nothing, does not store any variable in registers and always allocates and validates a stack frame, no name a few.
The extra abstractions when using a vector in Debug mode directly translate to more work for the CPU.

Related

Fastest Method to compute Linear interpolation between 2 points in QT using OpenGL

I'm trying to interpolate a triangle with the help of vertex coordinates.
a
|\
| \
| \
| \
b|_ _ _ \c
I'm interpolating the vertices in this order (b,a),(a,c)and (c,b).
Here the a,b and c are the 3 dimensional coordinates with a color value.
a = (x1,y1,z1,c1);
b = (x2,y2,z2,c2);
c = (x3,y3,z3,c3);
Structure used to compute the calculation:
struct pointsInterpolateStruct{
QList<double> x,y,z;
QList<double> r, g, b, clr;
void clear() {
x.clear();
y.clear();
z.clear();
r.clear();
g.clear();
b.clear();
clr.clear();
}
};
Interpolation Code:
QList<double> x,y,z,clrs;
This above mentioned lists has been used to read the values from a file which contains the coordinates of a,b and c.
/**
void interpolate();
#param1 ipts is an object for the point interpolation struct which holds the x,y,z and color
#param2 idx1 is the point A
#param 3idx2 is the point B
#return returns the interpolated values after filling the struct pointsInterpolateStruct
*/
void GLThread::interpolate(pointsInterpolateStruct *ipts,int idx1, int idx2) {
int ipStep = 0;
double delX, imX,iX,delY,imY,iY,delZ,imZ,iZ,delClr,imC,iC;
ipStep = 5; // number of points needed between the 2 points
delX = imX = iX = delY = imY = iY = delZ = imZ = iZ = delClr = imC = iC = 0;
delX = (x.at(idx2) - x.at(idx1));
imX = x.at(idx1);
iX = (delX / (ipStep + 1));
delY = (y.at(idx2) - y.at(idx1));
imY = aParam->y.at(idx1);
iY = (delY / (ipStep + 1));
delZ = (z.at(idx2) - z.at(idx1));
imZ = z.at(idx1);
iZ = (delZ / (ipStep + 1));
delClr = (clrs.at(idx2) - clrs.at(idx1));
imC = clrs.at(idx1);
iC = (delClr / (ipStep + 1));
ipts->clear();
int i = 0;
while(i<= ipStep) {
ipts->x.append((imX+ iX * i));
ipts->y.append((imY+ iY * i));
ipts->z.append((imZ+ iZ * i));
ipts->clr.append((imC + iC * i));
i++;
}
}*
Visualization of this interpolated points using OpenGL :
All the points are filled to vertices and color buffers and I'm drawing it using the below format. Visualization is very fast even for larger points.
void GLWidget::drawInterpolatedTriangle(void) {
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(3, GL_FLOAT, 0, clr);
glVertexPointer(3, GL_FLOAT, 0, vrt);
glPushMatrix();
glDrawArrays(GL_POLYGON, 0, vrtCnt);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
}
}
Now everything working fine. I'm getting the desired output. But the problem is when I'm trying to do the same for 'n' number of triangles (say n = 40,000), the application gets crashed even if I called this function in a QThread and I found that this method is not an efficient method as it takes lot of time for computation.
Please suggest an optimistic way to do this process so that I can achieve better results at good performance.
Output image :
Interpolated Triangle (point view)
Mesh View
Polygon View
After examining the memory used by the application, I found that there's large number of unwanted data has been stored in the list and arrays in my program (i.e., clearing the list x,y,z,r,g,b and clrs in pointsInterpolateStruct). I have cleared all the unwanted / unused data instantly and tried to run the application with larger triangles. Now I can achieve better performance. I didn't changed anything in visualization process.

Heap has been corrupted when using std::unique_ptr

I've been working on a Quake 3 BSP Loader in OpenGL and C++.
And I've ran into a problem, when I run my code. I get a problem, it says "heap has been corrupted!" in debug mode. I have commented the line it corrupts on. My comment is 'gives me the error at this line "Heap has been corrupted"'
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/vec3.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <vector>
#include "map.h"
#include <fstream>
#include <memory>
#include "game_manager.h"
#include <thread>
bool KikoBSP::load_map(std::string file_name)
{
this->file.open(file_name.c_str(), std::ios::in | std::ios::binary);
if (this->file.is_open())
{
this->file.read(reinterpret_cast<char*>(&this->header), sizeof(this->header));
std::unique_ptr<BSPEntities> ents(new BSPEntities);
ents->ents_array = new char[this->header.lumps[BSPLUMPS::ENTITIES].length];
this->num_textures = this->header.lumps[BSPLUMPS::TEXTURES].length / sizeof(BSPTexture);
this->num_planes = this->header.lumps[BSPLUMPS::PLANES].length / sizeof(BSPPlane);
this->num_textures = this->header.lumps[BSPLUMPS::TEXTURES].length / sizeof(BSPTexture);
this->num_nodes = this->header.lumps[BSPLUMPS::NODES].length / sizeof(BSPNode);
this->num_leafs = this->header.lumps[BSPLUMPS::LEAFS].length / sizeof(BSPLeaf);
this->num_leaf_faces = this->header.lumps[BSPLUMPS::LEAF_FACES].length / sizeof(BSPLeafFace);
this->num_leaf_brushes = this->header.lumps[BSPLUMPS::LEAF_BRUSHES].length / sizeof(BSPLeafBrush);
this->num_models = this->header.lumps[BSPLUMPS::MODELS].length / sizeof(BSPModel);
this->num_brushes = this->header.lumps[BSPLUMPS::BRUSHES].length / sizeof(BSPBrush);
this->num_brush_sides = this->header.lumps[BSPLUMPS::BRUSHSIDES].length / sizeof(BSPBrushSides);
this->num_vertexes = this->header.lumps[BSPLUMPS::VERTEXES].length / sizeof(BSPVerts);
this->num_meshverts = this->header.lumps[BSPLUMPS::MESHVERTS].length / sizeof(BSPMeshVerts);
this->num_effects = this->header.lumps[BSPLUMPS::EFFECTS].length / sizeof(BSPEffects);
this->num_faces = this->header.lumps[BSPLUMPS::FACES].length / sizeof(BSPFaces);
std::unique_ptr<BSPTexture[]> textures(new BSPTexture[this->num_textures]);
std::unique_ptr<BSPPlane[]> planes(new BSPPlane[this->num_planes]);
std::unique_ptr<BSPNode[]> nodes(new BSPNode[this->num_nodes]);
std::unique_ptr<BSPLeaf[]> leafs(new BSPLeaf[this->num_leafs]);
std::unique_ptr<BSPLeafFace[]> leaf_faces(new BSPLeafFace[this->num_leaf_faces]);
std::unique_ptr<BSPLeafBrush[]> leaf_brushes(new BSPLeafBrush[this->num_leaf_brushes]);
std::unique_ptr<BSPModel[]> models(new BSPModel[this->num_models]);
std::unique_ptr<BSPBrush[]> brushes(new BSPBrush[this->num_brushes]);
std::unique_ptr<BSPBrushSides[]> brush_sides(new BSPBrushSides[this->num_brush_sides]);
std::unique_ptr<BSPVerts[]> vertexes(new BSPVerts[this->num_vertexes]);
std::unique_ptr<BSPMeshVerts[]> mesh_verts(new BSPMeshVerts[this->num_mesh_verts]);
std::unique_ptr<BSPEffects[]> effects(new BSPEffects[this->num_effects]);
std::unique_ptr<BSPFaces[]> faces(new BSPFaces[this->num_faces]);
this->file.seekg(this->header.lumps[BSPLUMPS::ENTITIES].offset);
this->file.read(reinterpret_cast<char*>(ents->ents_array), this->header.lumps[BSPLUMPS::ENTITIES].length);
this->file.seekg(this->header.lumps[BSPLUMPS::TEXTURES].offset);
this->file.read(reinterpret_cast<char*>(textures.get()), this->header.lumps[BSPLUMPS::TEXTURES].length);
this->file.seekg(this->header.lumps[BSPLUMPS::PLANES].offset);
this->file.read(reinterpret_cast<char*>(planes.get()), this->header.lumps[BSPLUMPS::PLANES].length);
this->file.seekg(this->header.lumps[BSPLUMPS::NODES].offset);
this->file.read(reinterpret_cast<char*>(nodes.get()), this->header.lumps[BSPLUMPS::NODES].length);
this->file.seekg(this->header.lumps[BSPLUMPS::LEAFS].offset);
this->file.read(reinterpret_cast<char*>(leafs.get()), this->header.lumps[BSPLUMPS::LEAFS].length);
this->file.seekg(this->header.lumps[BSPLUMPS::LEAF_FACES].offset);
this->file.read(reinterpret_cast<char*>(leaf_faces.get()), this->header.lumps[BSPLUMPS::LEAF_FACES].length);
this->file.seekg(this->header.lumps[BSPLUMPS::LEAF_BRUSHES].offset);
this->file.read(reinterpret_cast<char*>(leaf_brushes.get()), this->header.lumps[BSPLUMPS::LEAF_BRUSHES].length);
this->file.seekg(this->header.lumps[BSPLUMPS::MODELS].offset);
this->file.read(reinterpret_cast<char*>(models.get()), this->header.lumps[BSPLUMPS::MODELS].length);
this->file.seekg(this->header.lumps[BSPLUMPS::BRUSHES].offset);
this->file.read(reinterpret_cast<char*>(brushes.get()), this->header.lumps[BSPLUMPS::BRUSHES].length);
this->file.seekg(this->header.lumps[BSPLUMPS::BRUSHSIDES].offset);
this->file.read(reinterpret_cast<char*>(brush_sides.get()), this->header.lumps[BSPLUMPS::BRUSHSIDES].length);
this->file.seekg(this->header.lumps[BSPLUMPS::VERTEXES].offset);
this->file.read(reinterpret_cast<char*>(vertexes.get()), this->header.lumps[BSPLUMPS::VERTEXES].length);
this->file.seekg(this->header.lumps[BSPLUMPS::MESHVERTS].offset);
this->file.read(reinterpret_cast<char*>(mesh_verts.get()), this->header.lumps[BSPLUMPS::MESHVERTS].length);
this->file.seekg(this->header.lumps[BSPLUMPS::EFFECTS].offset);
this->file.read(reinterpret_cast<char*>(effects.get()), this->header.lumps[BSPLUMPS::EFFECTS].length);
this->file.seekg(this->header.lumps[BSPLUMPS::FACES].offset);
this->file.read(reinterpret_cast<char*>(faces.get()), this->header.lumps[BSPLUMPS::FACES].length);
std::printf("BSP VERSION: '%s'\n", this->header.magic);
if (std::strncmp(this->header.magic, "IBSP", 4) == 0)
{
std::printf("SUCCESS: VALID BSP FORMAT!\n");
}
else
{
std::printf("ERROR: INVALID BSP FORMAT!\n");
return false;
}
std::printf("this->num_of_verts == %i\n", this->num_vertexes);
for (int32_t x = 0; x <= this->num_vertexes; x++)
{
this->vertices.push_back(vertexes.get()[x].position.x);
this->vertices.push_back(vertexes.get()[x].position.y); /* gives me the error at this line "Heap has been corrupted" */
this->vertices.push_back(vertexes.get()[x].position.z);
this->colors.push_back((float)x); /* doesnt follow my code style (using C-style cast), sorry!! I copied this from my old project ;) */
}
std::printf("this->vertices.size() == %i\n", this->vertices.size());
this->shader.load_shader("bsp.vs", "bsp.fs");
glGenVertexArrays(1, &this->vao);
glBindVertexArray(this->vao);
glGenBuffers(1, &this->vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(float), &this->vertices.front(), GL_STATIC_DRAW);
glGenBuffers(1, &this->color_vbo);
glBindBuffer(GL_ARRAY_BUFFER, this->color_vbo);
glBufferData(GL_ARRAY_BUFFER, this->colors.size() * sizeof(float), &this->colors.front(), GL_STATIC_DRAW);
this->coord3d = glGetAttribLocation(this->shader.program, "coord3d");
this->mvp = glGetUniformLocation(this->shader.program, "mvp");
this->attrib_color = glGetAttribLocation(this->shader.program, "v_color");
glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
glVertexAttribPointer(this->coord3d, // attribute
3, // number of elements per vertex, here (R,G,B)
GL_FLOAT, // the currentBlock of each element
GL_FALSE, // take our values as-is
0, // no extra data between each position
nullptr // offset of first element
);
glBindBuffer(GL_ARRAY_BUFFER, this->color_vbo);
glVertexAttribPointer(this->attrib_color,
3,
GL_FLOAT,
GL_FALSE,
0,
nullptr
);
glBindVertexArray(0);
glVertexAttrib3fv(this->attrib_color, this->colors.data());
std::printf("size of vector = %i\n", this->vertices.size());
return true;
}
else
{
std::printf("ERROR: COULDN'T OPEN FILE!\n");
return false;
}
return false;
}
void KikoBSP::render(glm::vec3 position)
{
glBindVertexArray(this->vao);
glEnableVertexAttribArray(this->coord3d);
glEnableVertexAttribArray(this->attrib_color);
glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(position.x, position.y, position.z));
glm::mat4 mvp = game_manager->projection * game_manager->view * model;
glUniformMatrix4fv(this->mvp, 1, GL_FALSE, glm::value_ptr(mvp));
glDrawArrays(GL_LINES, 0, this->vertices.size());
glDisableVertexAttribArray(this->coord3d);
glDisableVertexAttribArray(this->attrib_color);
glBindVertexArray(0);
}
void KikoBSP::cleanup_map()
{
/* OUTDATED FUNCTION BACK WHEN I WAS MANUALLY MANAGING MEMORY */
}
However, the error goes away, when I take off these lines:
this->file.seekg(this->header.lumps[BSPLUMPS::EFFECTS].offset);
this->file.read(reinterpret_cast<char*>(effects.get()), this->header.lumps[BSPLUMPS::EFFECTS].length);
this->file.seekg(this->header.lumps[BSPLUMPS::FACES].offset);
this->file.read(reinterpret_cast<char*>(faces.get()), this->header.lumps[BSPLUMPS::FACES].length);
Which leads me to believe the Heap is overflowing with all the allocated memory.
I also believe this, because when I was manually managing memory. I ran into the same problem as well. So I switched to unique_ptrs, and I'm still getting the same problem! :(
Anyone here have any ideas? Thanks! :)
You've got incorrect loop condition:
for (int32_t x = 0; x <= this->num_vertexes; x++)
In its last iteration x == num_vertexes, which means you are trying to read the value beyond the array boundary. Check with the debugger - you'll see that x takes this value when the heap corruption happens. Also, I'm pretty sure it's not the line you've marked causing heap corruption, but the line before - many debuggers show the next line to be executed, not the one being executed.
BTW I'm not familiar with the classes you use and thus can't say for sure, but you're most likely abusing the use of std::unique_ptr. Just use std::vector instead of unique pointer to dynamic array - it's way simplier, easier to use and should work exactly the way you expect.

Multiple quads in one vbo

I am working on a minecraft-ish game, and I've been working a little more with vbos. However; when drawing multiple faces in a single vbo I seem to have a little bit of a issue.
Here is my vbo-generation code:
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, verts);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, verts * 9 * sizeof(GLfloat), NULL, GL_STATIC_DRAW);
void* ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
GLfloat*model = (GLfloat*)ptr;
GLfloat*tex = ((GLfloat*)ptr) + verts * 6;
GLfloat*color = ((GLfloat*)ptr) + verts * 3;
int p = 0;
int k = p * 3;
for (int mcy = 0; mcy < 5; mcy++) {
for (int mcx = 0; mcx < 5; mcx++) {
double addonX = mcx*32.0;
double addonY = mcy*32.0;
int addonx = mcx * 32;
int addony = mcy * 32;
if (!(hill.get(addonX, addonY)*400.0 > 100 && hill.get(32 + addonX, addonY)*400.0 > 100 && hill.get(addonX, 32 + addonY)*400.0 > 100 && hill.get(32 + addonX, 32 + addonY)*400.0 > 100)) {
draw = true;
int biome1 = BiomeToColor(GetBiome(x, y, addonX, addonY), hill.get(addonX, addonY)*400.0);
int biome2 = BiomeToColor(GetBiome(x, y, 32 + addonX, addonY), hill.get(32 + addonX, addonY)*400.0);
int biome3 = BiomeToColor(GetBiome(x, y, addonX, 32 + addonY), hill.get(addonX, 32 + addonY)*400.0);
int biome4 = BiomeToColor(GetBiome(x, y, 32 + addonX, 32 + addonY), hill.get(32 + addonY, 32 + addonY)*400.0);
model[k] = addonx+ 32;
model[k + 1] = addony;
model[k + 2] = hill.get(addonX + 32, addonY)*400.0;
color[k] = BiomeColors[biome2].r;
color[k + 1] = BiomeColors[biome2].g;
color[k + 2] = BiomeColors[biome2].b;
p++;
k = p * 3;
model[k] = addonx + 32;
model[k + 1] = addony + 32;
model[k + 2] = hill.get(addonX + 32, addonY + 32)*400.0;
color[k] = BiomeColors[biome4].r;
color[k + 1] = BiomeColors[biome4].g;
color[k + 2] = BiomeColors[biome4].b;
p++;
k = p * 3;
model[k] = addonx;
model[k + 1] = addony + 32;
model[k + 2] = hill.get(addonX, addonY + 32)*400.0;
color[k] = BiomeColors[biome3].r;
color[k + 1] = BiomeColors[biome3].g;
color[k + 2] = BiomeColors[biome3].b;
p++;
k = p * 3;
model[k] = addony;
model[k + 1] = addony;
model[k + 2] = hill.get(addonX, addonY)*400.0;
color[k] = BiomeColors[biome1].r;
color[k + 1] = BiomeColors[biome1].g;
color[k + 2] = BiomeColors[biome1].b;
p++;
k = p * 3;
}
}
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
And here's the code I use to draw the vbo:
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexPointer(3, GL_FLOAT, 0, 0);
glTexCoordPointer(3, GL_FLOAT, 0, (char*)NULL + verts * 6 * sizeof(GLfloat));
glColorPointer(3, GL_FLOAT, 0, (char*)NULL + verts * 3 * sizeof(GLfloat));
glDrawArrays(GL_QUADS, 0, VBO);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Here's the result I want (using a single quad in every vbo):
unfortunatly I'm still new so you have to click this link :/
And here is the result I get with multiple quads in every vbo:
image
So why do I want to draw multiple quads in a single vbo?
One word: performance, if you compare the two images the thing that really pops out (well, except for the bug with the second image) is the framerate counter. I want to make this game into a big thing, so every fps matters to me.
EDIT:
Omg, I'm so stupid:
model[k] = addony;
A very simple mistake, but so devistating.
Just proves how so small things can brake the game.
It all workes now.
glDrawArrays(GL_QUADS, 0, VBO);
There are a few problems with this call:
the third parameter of glDrawArrays is the count of the things you are drawing so what you are actually saying is:
Draw Quads from my Buffer at 0 until VBO and then stop.
What you should be saying is:
Draw Quads from my Buffer at 0 until Buffer Length and then stop
so now it looks like this:
glDrawArrays(GL_QUADS, 0, verts);
'VBO' in your code is the ID of the Buffer that you want to use.
think about it like a pointer who's number you know or rather a user with an ID.
GL_QUADS is not good use GL_TRIANGLES there are many problems with GL_QUADS later especialy on mobile phones and on other platforms making your data in triangles is much much nicer.
You shouldn't be drawing in GL_QUADS for multiple reasons
Why are you not using VAO's? Are you using an older version of OpenGL that doesn't have VAO's? Otherwise I would suggest using VAO here instead of VBO so you dont need to bind pointers for each draw call.
glBindBuffer(GL_ARRAY_BUFFER, verts);
What you are trying to here is bind a VBO of id: 'verts' to be our current VBO.
'So why do I want to draw multiple quads in a single vbo? One word: performance'
Have you tried to draw multiple quads using instancing?
So sending a model matrix for each of the shapes so that you modify their positions and shapes in the shader and not in the buffer. This way you can draw one vbo over and over again just slightly transformed with a single draw call.
Here is a good tutorial on instancing:
http://learnopengl.com/#!Advanced-OpenGL/Instancing
Just out of curiosity but why did you decide to use:
glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
instead of buffering your data in the glBufferData call?
If you need to buffer the data later you can use glBufferSubData
Honestly though I think your performance problems stem from a range of factors.
I would personally use glBufferData instead of map data and when I need to do it during run time and not during loading I would use glBufferSubData.
I would upload the colors to the shader and draw multiples of the SAME VBO again and again with a different model matrix and colors allowing me to instance it.
However you shouldn't need to do that.
What I would recommend is making up the data in triangles and colors and drawing the whole ground as a mesh which you have seemed to tried to do. Your problem was most likely caused by glDrawArrays length being set to that of a VBO.
However in this case I would build a VBO using glBufferData with the size of a chunk then I would use glBufferSubData for each of the quads with colors etc. and once I am done I would draw that multiple times alongside different chunks.
I think it would be of use to you to do more theory of OpenGL.

Trying to draw text in OpenGL, but texture is offset slightly

I am trying to draw text in OpenGL. I used a small C# program to draw all characters from 0x21 to 0x7E into a bitmap. I load that as a texture and try to use that to draw my text. It appears to work, but I seem to get some weird problems. http://i54.tinypic.com/mmd7k8.png Notice the extra pixel next to 'a' and the fact that 'c' is cut off slightly. It appears the whole thing is shifted slightly. Does anybody know why I get this problem? I don't want to use a library such as gltext because I don't want to depend on libfreetype as I am only drawing a few strings. Here is the code that I am using:
static void textDrawChar(char c, int x, int y)
{
GLfloat vert[8];
GLfloat texcoord[8];
vert[0] = x; vert[1] = y;
vert[2] = x; vert[3] = y + TEXT_HEIGHT;
vert[4] = x + font_char_width[c-0x21]; vert[5] = y + TEXT_HEIGHT;
vert[6] = x + font_char_width[c-0x21]; vert[7] = y;
texcoord[0] = (float)(font_char_pos[c-0x21])/TOTAL_WIDTH;
texcoord[1] = 1.0f;
texcoord[2] = (float)(font_char_pos[c-0x21])/TOTAL_WIDTH;
texcoord[3] = 0.0f;
texcoord[4] = (float)(font_char_pos[c-0x21] + font_char_width[c-0x21])/TOTAL_WIDTH;
texcoord[5] = 0.0f;
texcoord[6] = (float)(font_char_pos[c-0x21] + font_char_width[c-0x21])/TOTAL_WIDTH;
texcoord[7] = 1.0f;
glBindTexture(GL_TEXTURE_2D, texture);
glVertexPointer(2, GL_FLOAT, 0, vert);
glTexCoordPointer(2, GL_FLOAT, 0, texcoord);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
}
void textDraw(void)
{
textDrawChar('a', 300, 300);
textDrawChar('b', 300+font_char_width['a'-0x21], 300);
textDrawChar('c', 300+font_char_width['a'-0x21]+font_char_width['b'-0x21], 300);
}
EDIT I added 4 to the texture coordinate (0,2,4,6) and that seems to have fixed the problem. However, now I need to know whether that will continue to work or may break for unknown reasons. Here is the bitmap creation code, in case the problem might be in there.
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
namespace font_to_bmp
{
class Program
{
static void Main(string[] args)
{
Bitmap b = new Bitmap(1715, 36);
Graphics g = Graphics.FromImage(b);
g.FillRectangle(new SolidBrush(Color.Transparent), 0, 0, 1715, 36);
Font f = new Font("Liberation Sans", 24, GraphicsUnit.Point);
g.PageUnit = GraphicsUnit.Pixel;
int curx = 0;
StreamWriter w = new StreamWriter(new FileStream("font_width.h", FileMode.Create, FileAccess.Write, FileShare.Read));
w.WriteLine("static const int font_char_width[] = {");
ArrayList hax = new ArrayList();
for (int i = 0x21; i <= 0x7E; i++)
{
char c = (char)i;
string s = c.ToString();
SizeF sz = g.MeasureString(s, f);
StringFormat sf = new StringFormat();
sf.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0,1)});
Region r = g.MeasureCharacterRanges(s, f, new RectangleF(0, 0, 1000, 1000), sf)[0];
RectangleF r2 = r.GetBounds(g);
Console.WriteLine("{0} is {1}x{2}", s, r2.Width, r2.Height);
int w_int = (int)(Math.Ceiling(r2.Width));
g.DrawString(s, f, new SolidBrush(Color.Black), curx, 0);
hax.Add(curx);
curx += w_int;
w.WriteLine("\t{0},", w_int);
}
Console.WriteLine("Total width {0}", curx);
w.WriteLine("};");
w.WriteLine();
w.WriteLine("static const int font_char_pos[] = {");
foreach(int z in hax)
{
w.WriteLine("\t{0},", z);
}
w.WriteLine("};");
w.Close();
b.Save("font.png");
}
}
}
Addressing the pixels exactly in a texture is a bit tricky. See my answer given in OpenGL Texture Coordinates in Pixel Space
This has been asked a few times, but I don't have the links at hand, so a quick and rough explanation. Let's say the texture is 8 pixels wide:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
^ ^ ^ ^ ^ ^ ^ ^ ^
0.0 | | | | | | | 1.0
| | | | | | | | |
0/8 1/8 2/8 3/8 4/8 5/8 6/8 7/8 8/8
The digits denote the texture's pixels, the bars the edges of the texture and in case of nearest filtering the border between pixels. You however want to hit the pixels' centers. So you're interested in the texture coordinates
(0/8 + 1/8)/2 = 1 / (2 * 8)
(1/8 + 2/8)/2 = 3 / (2 * 8)
...
(7/8 + 8/8)/2 = 15 / (2 * 8)
Or more generally for pixel i in a N wide texture the proper texture coordinate is
(2i - 1)/(2N)
However if you want to perfectly align your texture with the screen pixels, remember that what you specify as coordinates are not a quad's pixels, but edges, which, depending on projection may align with screen pixel edges, not centers, thus may require other texture coordinates.

QGLBuffer and VBO

I have a problem with QGLBuffer. I'm trying to implement a dynamic VBO with QT + Opengl.
In the .h file
struct CVert {
float x;
float y;
};
...
typedef struct CVert CVert;
CVert* m_data;
QGLBuffer* m_bufferData;
int m_size;
in the .cpp
Constructor.
m_size = numberOfVertex;
m_bufferData = new QGLBuffer(QGLBuffer::VertexBuffer);
m_bufferData->create();
m_bufferData->bind();
m_bufferData->setUsagePattern(QGLBuffer::DynamicDraw);
m_bufferData->allocate(2*sizeof(float)* p_size);
m_data = (CVert*)m_bufferData->map (QGLBuffer::ReadWrite);
In the execution of the program I change some m_data values
m_data[pos].x = X1
m_data[pos].y = y1
In the draw method.
glEnableClientState(GL_VERTEX_ARRAY);
if (m_bufferData->bind ()) {
glVertexPointer( 2, GL_FLOAT, 0, (char *) NULL );;
glDrawArrays( GL_LINES, 0,m_size );
glDisableClientState(GL_VERTEX_ARRAY);
}
But nothig it's being drawn.
I've checked that m_data is not null, and m_bufferData->bind() returns true.
What am I doing wrong?
I think i've solved. Every time i've to edit the VBO.
I have to
m_data = (CVert*)data->map (QGLBuffer::ReadWrite);
m_data[pos].x = X1;
m_data[pos].y = y1
data->unmap ();
it's doesn't work if I map only once in the constructor