So I made this gamish thing that uses a quickly-and-poorly made custom GUI library to manage the player interface. This thing currently consists in the drawing of a tile map, which is implemented using a sf::VertexArray of quads (basically a copy of the tutorial one...) and a TextBox object, also implemented using a vertex array of quads (since the tutorial made it look so efficent I figured I'd just spam it everywhere in my design
). The problem is that the two don't seem to get along nicely... when I try to draw them at the same time, the game crashes. This is what the debugger says about the crash (I'm using CodeBlocks with a recent version of mingw):
#0 0x53eb9f83 ig9icd32!RegisterProcTableCallback() (C:\WINDOWS\SysWOW64\ig9icd32.dll:??)
#1 0x53fea39c ig9icd32!RegisterProcTableCallback() (C:\WINDOWS\SysWOW64\ig9icd32.dll:??)
#2 0x5409c9d4 ig9icd32!RegisterProcTableCallback() (C:\WINDOWS\SysWOW64\ig9icd32.dll:??)
#3 0x5409c642 ig9icd32!RegisterProcTableCallback() (C:\WINDOWS\SysWOW64\ig9icd32.dll:??)
#4 0x5409c3e2 ig9icd32!RegisterProcTableCallback() (C:\WINDOWS\SysWOW64\ig9icd32.dll:??)
#5 0x53ebea1a ig9icd32!RegisterProcTableCallback() (C:\WINDOWS\SysWOW64\ig9icd32.dll:??)
#6 0x53ebeadf ig9icd32!RegisterProcTableCallback() (C:\WINDOWS\SysWOW64\ig9icd32.dll:??)
#7 0x54208ad3 ig9icd32!RegisterProcTableCallback() (C:\WINDOWS\SysWOW64\ig9icd32.dll:??)
#8 0x66b9c466 sf::RenderTarget::draw(sf::Vertex const*, unsigned int, sf::PrimitiveType, sf::RenderStates const&) () (C:\Code\C\sfml\Wars\sfml-graphics-2.dll:??)
#9 0x66baa258 sf::VertexArray::draw(sf::RenderTarget&, sf::RenderStates) const() (C:\Code\C\sfml\Wars\sfml-graphics-2.dll:??)
#10 0x66b9b87c sf::RenderTarget::draw(sf::Drawable const&, sf::RenderStates const&) () (C:\Code\C\sfml\Wars\sfml-graphics-2.dll:??)
#11 0x403a75 _fu21___ZSt4cout() (C:\Code\C\sfml\Wars\src\interface\TextBox.cpp:101)
And here's the part of the code where the game breaks:
//draw
void TextBox::parentDraw(sf::RenderTarget& target, sf::RenderStates states) const {
//if no font is set, abort
assert(mTextInfo.font);
//update vertices if necessary
if(mNeedToUpdateVertices){
std::cout << "text: " << mTextInfo.text << "\n\n";
mNeedToUpdateVertices = false;
//calculate new vertex array size needed
//(updated constantly when special (not printable) characters
// are handled and used at the end to resize the vertex array)
size_t verticesNum = 0;
for(const auto& ele : mTextInfo.text) verticesNum++;
mVertices.resize(verticesNum * 4);
//adjust vertex array
const auto& newText = mTextInfo.text;
unsigned int lineOffset = getBounds().left;
unsigned int verticalOffset = getBounds().top + mTextInfo.font->getLineSpacing(mTextInfo.charSize);
for(size_t j = 0, vj = 0; j < newText.size(); j++, vj++){
//handle special characters
if(newText[j] == '\n'){
verticesNum--;
vj--;
lineOffset = getBounds().left;
verticalOffset += mTextInfo.font->getLineSpacing(mTextInfo.charSize);
}
//handle letters (non-handled characters are rendered as letters)
else {
//handle space
if(newText[j] == ' '){
//generate a new line
auto futLineOffset = lineOffset;
auto k = j + 1;
for(; newText[k] != ' ' && newText[k] != '\n' && k < newText.size(); k++){
futLineOffset += mTextInfo.font->getGlyph(newText[k], mTextInfo.charSize, false).advance;
}
if(futLineOffset > getBounds().width){
verticesNum--;
j++;
lineOffset = getBounds().left;
verticalOffset += mTextInfo.font->getLineSpacing(mTextInfo.charSize);
}
}
//change vertex quad associated with letter
auto glyph = mTextInfo.font->getGlyph(newText[j], mTextInfo.charSize, false);
auto bRect = glyph.bounds;
float kerning = 0;
//handle kerning
if(j < newText.size() - 1)
kerning = mTextInfo.font->getKerning(newText[j], newText[j+1], mTextInfo.charSize);
//set glyph bounds within text box
bRect.left = lineOffset + kerning;
lineOffset += glyph.advance + kerning;
bRect.top += verticalOffset;
//get texture rect
const auto& tRect = glyph.textureRect;
//convert glyph into vertex quad
mVertices[vj*4] = sf::Vertex({bRect.left, bRect.top}, {tRect.left, tRect.top});
mVertices[vj*4 + 1] = sf::Vertex({bRect.left + bRect.width, bRect.top}, {tRect.left + tRect.width, tRect.top});
mVertices[vj*4 + 2] = sf::Vertex({bRect.left + bRect.width, bRect.top + bRect.height}, {tRect.left + tRect.width, tRect.top + tRect.height});
mVertices[vj*4 + 3] = sf::Vertex({bRect.left, bRect.top + bRect.height}, {tRect.left, tRect.top + tRect.height});
}
//handle horizontal overflow
if(lineOffset >= getBounds().width){
lineOffset = getBounds().left;
verticalOffset += mTextInfo.font->getLineSpacing(mTextInfo.charSize);
}
}
//resize vertex array if necessary (special characters were encountered)
if(mVertices.getVertexCount() != verticesNum * 4)
mVertices.resize(verticesNum * 4);
}
//set transform
states.transform *= getTransform();
//set texture
states.texture = &(mTextInfo.font->getTexture(mTextInfo.charSize));
//draw vertex array to render target
target.draw(mVertices, states);
}
Again, the problem only comes up when I draw a TextBox object (or really anything else - even using an object from a less-poorly made GUI library, such as TGUI, causes a segmentation fault) in conjunction with the tilemap; which is implemented as such (I'll only put the draw method here, but I'm willing to post more code on request):
void World::draw(sf::RenderTarget& target, sf::RenderStates states) const {
if(mNeedToUpdateVertices){
//update vertices if needed
for(int x = 0; x < mWidth; x++){
for(int y = 0; y < mHeight; y++){
if(mNeedToUpdateAllVertices || mPositionsToUpdate[y * mWidth + x]){
//determine which tile to show
auto tile = getTile({x, y});
sf::IntRect groundTR;
if(tile.up == UpTile::Air){
groundTR = sf::IntRect(gTerrainTileModels[tile.terrain].info.textureRect);
}
else{
groundTR = sf::IntRect(gUpTileModels[tile.up].info.textureRect);
}
//add up/terrain vertices
updateQuadAtPosition(sf::Vector2i(x, y), groundTR, false);
//add area vertices
updateQuadAtPosition(sf::Vector2i(x, y), gUpTileModels[tile.area].info.textureRect, true);
}
}
}
//render entities
for(const auto& entity : mEntities){
const auto& pos = entity->getPosition();
if(mNeedToUpdateAllVertices || mPositionsToUpdate[pos.y * mWidth + pos.x])
updateQuadAtPosition(pos, entity->getTextureRect(), false);
}
}
//apply transform
states.transform = getTransform();
//set texture
states.texture = mTileSheetTexture;
//reset positions to update
mNeedToUpdateVertices = false;
mNeedToUpdateAllVertices = false;
for(auto q = mPositionsToUpdate.begin(); q != mPositionsToUpdate.end(); ++q)
*q = false;
//render vertices
target.draw(mVertices, states);
}
void World::updateQuadAtPosition(const sf::Vector2i& pos, const sf::IntRect& textureRect, bool isArea) const {
auto index = (pos.y * mWidth + pos.x) * 8;
if(isArea) index += 4;
sf::FloatRect rr = {pos.x * World::TILE_WIDTH,
pos.y * World::TILE_HEIGHT,
World::TILE_WIDTH,
World::TILE_HEIGHT};
const auto& tr = textureRect;
//add up/terrain vertices
mVertices[index] = sf::Vertex({rr.left, rr.top}, {tr.left, tr.top});
mVertices[index + 1] = sf::Vertex({rr.left + rr.width, rr.top}, {tr.left + tr.width, tr.top});
mVertices[index + 2] = sf::Vertex({rr.left + rr.width, rr.top + rr.height}, {tr.left + tr.width, tr.top + tr.height});
mVertices[index + 3] = sf::Vertex({rr.left, rr.top + rr.height}, {tr.left, tr.top + tr.height});
}
And here's where I draw the two:
void MatchHandler::handleDrawing()
{
//draw player view of world
auto standardView = mWindow->getDefaultView();
auto playerView = mPlayer->calcView();
playerView.setViewport(sf::FloatRect(0.f, 0.f, 0.5, 1.f));
mWindow->setView(playerView);
mWindow->draw(*mWorld);
//draw player interface
mWindow->setView(standardView);
mWindow->draw(*(mPlayerInterface->getChild("message_box")));
}
I know this is a long question, but I really tried everything before posting. Also, I repeat, the problem is not specific to this instance of it, and happens even when I use other GUI libraries or just anything that is implemented using sf::VertexArray.
Thaks in advance for any response
.