Closed Nathan-M-code closed 2 months ago
I slightly changed your code to read shaders from a string(since I don't know what does the readBinary
do and how to test with it):
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
std::string vert = R"(#version 100
attribute vec2 position;
attribute vec4 color;
attribute vec2 texCoord;
varying vec4 sf_color;
varying vec2 sf_texCoord;
uniform mat4 sf_modelview;
uniform mat4 sf_projection;
void main()
{
vec2 pos = position;
sf_color = color;
sf_texCoord = texCoord;
gl_Position = sf_projection * sf_modelview * vec4(pos.xy, 0.0, 1.0);
})";
std::string frag = R"(#version 100
precision mediump float;
varying vec4 sf_color;
varying vec2 sf_texCoord;
uniform sampler2D sf_sampler;
uniform mat4 sf_texture;
void main()
{
vec4 coord = sf_texture * vec4(sf_texCoord, 0.0, 1.0);
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * texture2D(sf_sampler, coord.xy);
})";
int main()
{
sf::RenderWindow window(sf::VideoMode::getDesktopMode(), "Test", sf::Style::Fullscreen);
sf::Texture t;
t.loadFromFile("Res/settings.png");
sf::Shader s;
if(!s.loadFromMemory(vert, frag)){
sf::err() << "a";
}
//not necessary
s.setUniform("sf_sampler", sf::Shader::CurrentTexture);
sf::Clock clock;
sf::Sprite sprite(t);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed) window.close();
}
window.clear();
//also not necessary
s.setUniform("time", clock.getElapsedTime().asSeconds());
window.draw(sprite, &s);
window.display();
}
return EXIT_SUCCESS;
}
This works completely fine, so your error might be somewhere in getting the shader source code?
Yes the code is working, it is my test program. In my real game, the code is more or less the same with some layer of complexity added. I am looking for the difference that could lead to invisible sprites. I was wondering if you had any idea where the problem could come from, whether in loading, or in shader uniform setting for example. What is weird is that everything seem fine in logs. No err message, and it is just the sprite with shaders.
Without more information, I honestly have no clue, sorry.
Yeah sure I should have given a reproducible example at first here we go
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <android/log.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/native_activity.h>
#include <android/configuration.h>
#include <SFML/System/NativeActivity.hpp>
#include <filesystem>
#define LOG(...) ((void)__android_log_print(ANDROID_LOG_INFO, "FC", __VA_ARGS__))
std::vector<std::uint8_t> readBinary(std::filesystem::path path, bool internalStorage=false)
{
std::vector<std::uint8_t> ret;
ANativeActivity* nativeActivity = sf::getNativeActivity();
AAssetManager* assetManager = nativeActivity->assetManager;
AAsset* mAsset = AAssetManager_open(assetManager, path.c_str(), AASSET_MODE_BUFFER);
if(!mAsset){
LOG("Can't open file");
return ret;
}
int len = AAsset_getLength(mAsset);
ret.resize(len); // Allocate memory for the vector
int lenRead = AAsset_read(mAsset,ret.data(),len);
AAsset_close(mAsset);
LOG("Read %s bytes", std::to_string(lenRead).c_str());
return ret;
}
sf::Shader* requestShader()
{
auto s = new sf::Shader;
auto bytesVertexShader = readBinary("minimal.vert.android");
std::string vertexShader(bytesVertexShader.begin(), bytesVertexShader.end());
LOG("vertexShader: %s", vertexShader.c_str());
auto bytes = readBinary("red.frag.android");
std::string fragShader(bytes.begin(), bytes.end());
LOG("fragShader: %s", fragShader.c_str());
if(!s->loadFromMemory(vertexShader, fragShader)){
throw std::runtime_error("Couldn't compile");
}
s->setUniform("sf_sampler", sf::Shader::CurrentTexture);
LOG("loaded !");
return s;
}
int main()
{
sf::RenderWindow window(sf::VideoMode::getDesktopMode(), "Test", sf::Style::Fullscreen);
sf::Texture t;
t.loadFromFile("image.png");
sf::Sprite sprite(t);
sf::Clock clock;
sf::Shader* s = nullptr;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed) window.close();
if (event.type == sf::Event::TouchBegan){
s = requestShader();
}
}
window.clear();
window.draw(sprite, s);
window.display();
}
return EXIT_SUCCESS;
}
The problem seems to come when we load shader at runtime.
Logs show that reading files is ok, I can see them through LOG("fragShader: %s", fragShader.c_str());
and LOG("vertexShader: %s", vertexShader.c_str());
, and the compilation is fine.
Once the shader is applied, the sprite is invisible.
By the way, I use readBinary
to load files from android assets folder, as loadFromFile
loads only the internal storage with std::ifstream
.
Uhhh, I'm pretty sure it is the opposite way around, loadFromFile
reads the assets folder in the APK, while with std::ifstream
you can read from anywhere on the device (as long as you have permission).
At least I've been using loadFromFile for loading read-only resources/assets and std::ifstream
and std::ofstream
for things like save files.
At least I've been using loadFromFile for loading read-only resources/assets and std::ifstream and std::ofstream for things like save files.
Yes, the loadFromFile from class sf::Shader
uses std::ifstream
while other loadFromFile
from other classes (sf::Texture
for example) are linked with Android specific code that reads assets.
I think they did not do the same thing with sf::Shader
because opening a shader in android was irrelevant.
Did you succeed to run the minimal example ? Should this issue be reopen ? If you have an idea of what the problem could be, I can have a look at it and maybe pr something.
I've been busy last week, so sorry for this late reply. I've tested this and again, I am not familiar with what should I do outside the program which is likely the reason I'm getting the error "Can't open file". Anyways I see now that sf::Shader uses std::ifstream so I think I'll change it to use sf::FileInputStream to be the same as sf::Texture sf::Font and so on which all load from the assets folder.
It is weird that you get "Can't open file" with the program I gave if the shaders are in the asset folder. Anyway I think the problem comes from loading shader at runtime, because I have the same issue with this program :
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <android/log.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/native_activity.h>
#include <android/configuration.h>
#include <SFML/System/NativeActivity.hpp>
#include <filesystem>
#define LOG(...) ((void)__android_log_print(ANDROID_LOG_INFO, "FC", __VA_ARGS__))
std::string vert = R"(#version 100
attribute vec2 position;
attribute vec4 color;
attribute vec2 texCoord;
varying vec4 sf_color;
varying vec2 sf_texCoord;
uniform mat4 sf_modelview;
uniform mat4 sf_projection;
void main()
{
vec2 pos = position;
sf_color = color;
sf_texCoord = texCoord;
gl_Position = sf_projection * sf_modelview * vec4(pos.xy, 0.0, 1.0);
})";
std::string frag = R"(#version 100
precision mediump float;
varying vec4 sf_color;
varying vec2 sf_texCoord;
uniform sampler2D sf_sampler;
uniform mat4 sf_texture;
void main()
{
vec4 coord = sf_texture * vec4(sf_texCoord, 0.0, 1.0);
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * texture2D(sf_sampler, coord.xy);
})";
sf::Shader* requestShader()
{
auto s = new sf::Shader;
if(!s->loadFromMemory(vert, frag)){
throw std::runtime_error("Couldn't compile");
}
s->setUniform("sf_sampler", sf::Shader::CurrentTexture);
LOG("loaded !");
return s;
}
int main()
{
sf::RenderWindow window(sf::VideoMode::getDesktopMode(), "Test", sf::Style::Fullscreen);
sf::Texture t;
t.loadFromFile("image.png");
sf::Sprite sprite(t);
sf::Clock clock;
sf::Shader* s = nullptr;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed) window.close();
if (event.type == sf::Event::TouchBegan){
s = requestShader();
}
}
window.clear();
window.draw(sprite, s);
window.display();
}
return EXIT_SUCCESS;
}
And I get "loaded !" in logs
The merge #12 fixed the issue ! Thank you all
Prerequisite Checklist
Describe your issue here
Sorry it is not really an error but I am struggling to find my mistake. I did a test application to test shaders and it works well. But when I ported that on my actual game, all sprites with shader are just invisible. These are my shaders vertex :
fragment :
Again, that is working with a little test application :
I was wondering what could be the problem that leads to invisible sprite ? The compilation is fine, no sfml's error in logs. I checked with wrong shader and I've got error message. Any clue ? Thank you
Your Environment
Steps to reproduce
I am looking for step to reproduce my problem
Expected behavior
working shaders
Actual behavior
invisible sprite