Hi, I've rewritten the SFML classes for the 3D so I just added a z component in the SFML Graphics module, I had also to copy some SFML classes (Texture, RenderTexture, TextureSaver, RenderTextureImple, etc...) in my own project because the m_cache_id and other texture informations used by SFML are only accessible by SFML classes. (because these informations are internal to SFML)
I didn't changed anything for the textures and rendertextures management classe except the namspace nam of course.
But Opengl give me some error message when I delete the render texture, and, especially when they are static, here is the classe which hold the render textures :
#ifndef ODFAEG_TILEMAP_HPP
#define ODFAEG_TILEMAP_HPP
#include "../renderTexture.h"
#include "tile.h"
#include "../shader.h"
namespace odfaeg {
namespace g2d {
class TileMap : public Entity
{
public:
TileMap (View& view, const Texture* tileset) : view(view) ,
Entity (Vec3f (view.getPosition().x, view.getPosition().y, 0), Vec3f(view.getSize().x, view.getSize().y, 0), Vec3f(view.getSize().x * 0.5f, view.getSize().y * 0.5f, 0), "E_TILEMAP") {
this->view = view;
// load the tileset texture
m_tileset = tileset;
}
static void genBuffers(unsigned int screenWidth, unsigned int screenHeight) {
resolution = Vec2f(screenWidth, screenHeight);
if (Shader::isAvailable()) {
depthBuffer.create(screenWidth, screenHeight);
frameBuffer.create(screenWidth, screenHeight);
const std::string vertexShader = \
"void main () {" \
"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" \
"gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;" \
"gl_FrontColor = gl_Color;" \
"}";
const std::string depthGenFragShader = \
"uniform sampler2D depthBuffer;" \
"uniform vec2 resolution;" \
"void main () {" \
"vec2 position = ( gl_FragCoord.xy / resolution.xy );" \
"vec4 pixel = texture2D(depthBuffer, position);" \
"if (gl_FragCoord.z > pixel.z) {" \
"gl_FragColor = vec4(0, 0, gl_FragCoord.z, 1);" \
"} else {" \
"gl_FragColor = gl_Color * pixel;" \
"}" \
"}";
const std::string frameBufferGenFragShader = \
"uniform sampler2D depthBuffer;" \
"uniform sampler2D frameBuffer;" \
"uniform sampler2D texture;" \
"uniform vec2 resolution;" \
"void main () { " \
"vec2 position = ( gl_FragCoord.xy / resolution.xy );" \
"vec4 depth = texture2D(depthBuffer, position);" \
"vec4 color = texture2D(frameBuffer, position);" \
"vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);" \
"vec4 finalColor = pixel;" \
"if (gl_FragCoord.z >= depth.z) {" \
"gl_FragColor = finalColor;" \
"} else if (color.a < finalColor.a) {" \
"float delta = finalColor.a - color.a;" \
"gl_FragColor = color + vec4(finalColor.r * delta, finalColor.g * delta, finalColor.b * delta, delta);" \
"} else {" \
"gl_FragColor = color;" \
"}" \
"}";
if (!depthBufferGenerator.loadFromMemory(vertexShader, depthGenFragShader))
throw Erreur(50, "Failed to load depth buffer generator shader", 0);
if (!frameBufferGenerator.loadFromMemory(vertexShader, frameBufferGenFragShader))
throw Erreur(51, "Failed to load frame buffer generator shader", 0);
depthBufferGenerator.setParameter("resolution",resolution.x, resolution.y);
frameBufferGenerator.setParameter("resolution",resolution.x, resolution.y);
}
}
static void clearBufferBits(sf::Color color) {
frameBuffer.clear(sf::Color(color.r, color.g, color.b, 0));
}
static void clearDepthBits() {
depthBuffer.clear(sf::Color(0, 0, 0, 255));
}
bool load(std::vector<Tile*> tiles, sf::PrimitiveType pType = sf::Quads)
{
// resize the vertex array to fit the level size
m_vertices.setPrimitiveType(pType);
m_vertices.resize(tiles.size() * 4);
// populate the vertex array, with one quad per tile
for (unsigned int i = 0; i < tiles.size(); i++) {
// get a pointer to the current tile's quad
//Vertex* quad = &m_vertices[i * 4];
Vec2f position (tiles[i]->getPosition().x, tiles[i]->getPosition().y);
float zOrder = tiles[i]->getPosition().z - view.getSize().z + 1;
Vec2f size = Vec2f(tiles[i]->getSize().x, tiles[i]->getSize().y);
sf::IntRect subRect = tiles[i]->getTextureRect();
// define its 4 corners
m_vertices[i*4].position = sf::Vector3f(position.x, position.y, zOrder);
m_vertices[i*4+1].position = sf::Vector3f(position.x + size.x, position.y, zOrder);
m_vertices[i*4+2].position = sf::Vector3f(position.x + size.x, position.y + size.y, zOrder);
m_vertices[i*4+3].position = sf::Vector3f(position.x, position.y + size.y, zOrder);
// define its 4 texture coordinates
m_vertices[i*4].texCoords = sf::Vector2f(subRect.left, subRect.top);
m_vertices[i*4+1].texCoords = sf::Vector2f(subRect.left + subRect.width, subRect.top);
m_vertices[i*4+2].texCoords = sf::Vector2f(subRect.left + subRect.width, subRect.top + subRect.height);
m_vertices[i*4+3].texCoords = sf::Vector2f(subRect.left, subRect.top + subRect.height);
}
return true;
}
static Tile getFrameBufferTile () {
sf::IntRect subRect(0, 0, frameBuffer.getView().getSize().x, frameBuffer.getView().getSize().y);
Tile tile (&frameBuffer.getTexture(), Vec2f(frameBuffer.getView().getPosition().x, frameBuffer.getView().getPosition().y), Vec2f(frameBuffer.getView().getSize().x, frameBuffer.getView().getSize().y), subRect, 0);
return tile;
}
static Tile getDepthBufferTile() {
sf::IntRect subRect(0, 0, depthBuffer.getView().getSize().x, depthBuffer.getView().getSize().y);
Tile tile (&depthBuffer.getTexture(), Vec2f(depthBuffer.getView().getPosition().x, depthBuffer.getView().getPosition().y), Vec2f(depthBuffer.getView().getSize().x, depthBuffer.getView().getSize().y), subRect, 0);
return tile;
}
bool isAnimated() const {
return false;
}
bool selectable() const {
return false;
}
bool isModel() const {
return false;
}
bool isShadow() const {
return false;
}
bool isLight() const {
return true;
}
const Texture* getTileset() {
return m_tileset;
}
bool operator==(Entity& other) {
if (other.getType() != "E_TILEMAP")
return false;
TileMap& tm = static_cast<TileMap&>(other);
return m_tileset == tm.m_tileset;
}
void clear() {
m_vertices.clear();
}
virtual void onDraw(RenderTarget& target, RenderStates states) const
{
// apply the transform
states.texture = m_tileset;
if (Shader::isAvailable()) {
states.shader = &frameBufferGenerator;
//Update the depth buffer and the frame buffer of the current frame.
frameBufferGenerator.setParameter("depthBuffer", depthBuffer.getTexture());
frameBufferGenerator.setParameter("frameBuffer", frameBuffer.getTexture());
frameBufferGenerator.setParameter("texture", Shader::CurrentTexture);
frameBuffer.setView(view);
frameBuffer.draw(m_vertices, states);
frameBuffer.display();
//Update the depth buffer.
depthBuffer.setView(view);
depthBufferGenerator.setParameter("depthBuffer", depthBuffer.getTexture());
states.shader = &depthBufferGenerator;
depthBuffer.draw(m_vertices, states);
depthBuffer.display();
states.shader = nullptr;
states.transform = getTransform();
Tile tile = getFrameBufferTile();
tile.move(Vec3f(-view.getSize().x * 0.5f, -view.getSize().y * 0.5f, 0));
target.draw(tile, states);
} else {
states.transform = getTransform();
target.draw(m_vertices, states);
}
}
private:
static Shader& getShader() {
static Shader shader;
return shader;
}
static RenderTexture& getRenderTexture() {
static RenderTexture renderTexture;
return renderTexture;
}
VertexArray m_vertices;
const Texture* m_tileset;
static RenderTexture depthBuffer;
static RenderTexture frameBuffer;
static Shader& depthBufferGenerator;
static Shader& frameBufferGenerator;
static Vec2f resolution;
View& view;
};
}
}
#endif // TILEMAP
When I close the application I have this error message :
An internal OpenGL call failed in renderTextureImplFBO.cpp (65) : GL_INVALID_VALUE, a numeric argument is out of range.
I've printed the frameBuffer id in the console and they are correct (1 for the frameBuffer render texture and 2 for the depthBuffer render texture)
I've a question so, is it a problem if the renderwindow is destroyed before the RenderTextures ?
But even if I don't destroy the window, the problem remains....