I wrote a shader that generates noise, it uses gl_TexCoord[0].xy (a thing generated by SFML) as input and outputs a float for every pixel.
I want the data on the CPU, as an array of 32bits float.
Here is what I'm doing:
//using opengl 3.0 (I also tried 3.2)
ContextSettings settings(0, 0, 0, 3, 0);
sf::RenderWindow window(sf::VideoMode(windowsize.x, windowsize.y),
"yada", 7, settings
);
Here I overwrite the texture after the texture is created:
#ifndef GL_R32F
#define GL_R32F 0x822E // found this in glad.h for opengl 3.0, easy guess is that this value doesn't change across opengl versions
#endif
auto handle = sprite_perlin.getTexture()->getNativeHandle();
glBindTexture(GL_TEXTURE_2D, handle);
auto size = sprite_perlin.getTexture()->getSize();
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, size.x, size.y, 0, GL_RED, GL_FLOAT, NULL);
}
Here I read the texture data into values:
float values[4096];
// whole_size is the size of the texture, here it is 60
if(whole_size*whole_size < 4096)
glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, values);
Image brought_back;
brought_back.create(whole_size, whole_size, Color::Red);
float mi = 1e20, ma = -1e20;
for (int i = 0; i < whole_size; ++i) {
for (int j = 0; j < whole_size; ++j) {
brought_back.setPixel(i, j, { 0,Uint8(255.f*values[whole_size*i + j]),0 });
ma = max(values[whole_size*i + j], ma);
mi = min(values[whole_size*i + j], mi);
}
}
mi and ma are both to 0.0f;
Here is the noise generated when showed on a sprite with the shader (with some color function that takes a float) The shader works as intended, I would just like to retrieve the data as float on the CPU.
Here is a simplified version of the shader:
uniform int texture_size;
float get_value_at(ivec2 pixel_coord) {
//dummy value
return 0.34f;
}
void main(){
ivec2 pix_pos = ivec2(gl_TexCoord[0].xy*texture_size);
float val = get_value_at(pix_pos);
gl_FragColor = vec4(val,0,0,1);
}
Here is an updated code, which is using rendertexture to test things out (sorry it's 417 lines, but it should work as is):
//#include "stdafx.h"
#include <random>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <SFML/OpenGL.hpp>
//#include <Box2D\Box2D.h>
using namespace std;
using namespace sf;
typedef Vector2f Vec2;
typedef Vector2<double> Vec2d;
typedef Vector2i Vec2i;
float interp(float start, float end, float coef) { return (end - start)*coef + start; }
Vec2 interp(Vec2 start, Vec2 end, float coef) { return coef * (end - start) + start; }
vector<float> seeded_rand_float(unsigned int seed, int many) {
vector<float> ret;
std::mt19937 rr;
std::uniform_real_distribution<float> dist(0, 1.0);
rr.seed(seed);
for (int j = 0; j < many; ++j)
ret.push_back(dist(rr));
return ret;
}
vector<Vec2> seeded_rand_vec2(unsigned int seed, int many) {
auto coeffs1 = seeded_rand_float(seed, many * 2);
vector<Vec2> pushere;
for (int i = 0; i < many; ++i)
pushere.push_back(Vec2(coeffs1[2 * i], coeffs1[2 * i + 1]));
return pushere;
}
#define msg(s) cout<< #s << " " << s << endl;
RenderWindow * window;
RenderTarget * target;
namespace labground {
Vec2 winsize, wincenter;
Vec2i windowsize;
Vec2 mpos_abs, mpos;
//logfile lf;
//configfile cfg;
Transform transf_glob;
Vec2 tr(Vec2 p) {
return transf_glob.transformPoint(p);
};
Vec2 untr(Vec2 p) {
return transf_glob.getInverse().transformPoint(p);
};
View view, ui_view;
// zooming
float zoom_mult = 1.5f;
float zoom_div = 1.0f / zoom_mult;
float zoomlevel = 1;
void zoom (Event&e) {
using namespace labground;
mpos_abs = window->mapPixelToCoords(Vec2i(mpos), view);
// msg(view.getSize());
// msg(view.getCenter());
//view = window->getView();
if (e.mouseWheel.delta < 0) {
zoomlevel *= zoom_mult;
view.setSize(view.getSize()*zoom_mult);
auto center = interp(mpos_abs, view.getCenter(), zoom_mult);
center = Vec2(Vec2i(center));
view.setCenter(center);
}
if (e.mouseWheel.delta > 0) {
zoomlevel *= zoom_div;
view.setSize(view.getSize()*zoom_div);
auto center = interp(mpos_abs, view.getCenter(), zoom_div);
view.setCenter(center);
}
window->setView(view);
};
}
namespace perlin_shading {
Shader perlin_shader;
sf::Texture texture_shader, texture_broughtback;
sf::Sprite sprite_perlin, sprite_broughtback, sprite_rtext;
Image img_back;
typedef Vec2i ivec2;
typedef Vec2 vec2;
float sprite_scale;
int grad_size, grad_quant, whole_size;
Vec2 gradients[16];
Vec2 gradients_ctype[4096];
RenderTexture rtext;
void init_perlin() {
perlin_shader.loadFromFile("shaders/perlin-better.frag", sf::Shader::Fragment);
//perlin_shader.loadFromFile("shaders/" + cfg.getstr("shader_file"), sf::Shader::Fragment);
//perlin_shader.loadFromFile("shaders/noisebench.vert", "shaders/" + cfg.getstr("shader_file"));
perlin_shader.setUniform("grad_size", grad_size);
perlin_shader.setUniform("grad_quant", grad_quant);
//perlin_shader.setUniformArray("gradients", gradients, grad_quant*grad_quant);
perlin_shader.setUniformArray("gradients", gradients_ctype, grad_quant*grad_quant);
//texture.loadFromFile("pics/orxqx6B.png");
//sprite_perlin.move(wincenter);
Image img;
//img.create(400, 400, Color::Black);
img.create(whole_size, whole_size, Color::Red);
for (int i = 0; i < 10; ++i) {
img.setPixel(i * 2, i, Color::Green);
img.setPixel(i, i * 2, Color::Red);
img.setPixel(i, i, Color::Yellow);
img.setPixel(i / 2, i, Color::Cyan);
img.setPixel(i, i / 2, Color::Magenta);
}
texture_shader.loadFromImage(img);
//shader.setUniform("texture", sf::Shader::CurrentTexture);
//perlin_shader.setUniform("v_texCoord4D", Glsl::Vec4(1,1,1,1));
sprite_perlin.setTexture(texture_shader);
{
#ifndef GL_R32F
#define GL_R32F 0x822E
#endif
auto handle = sprite_perlin.getTexture()->getNativeHandle();
glBindTexture(GL_TEXTURE_2D, handle);
auto size = sprite_perlin.getTexture()->getSize();
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, size.x, size.y, 0, GL_RED, GL_FLOAT, NULL);
}
sprite_perlin.move(labground::wincenter);
sprite_perlin.setScale(sprite_scale, sprite_scale);
//sprite_perlin.setScale(sprite_scale, sprite_scale);
}
void pull_data() {
using namespace perlin_shading;
float values[4096];
/*
void glGetTexImage(
GLenum target,
GLint level,
GLenum format,
GLenum type,
GLvoid * pixels);
void glTexImage2D( GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const GLvoid * data);
void glReadPixels( GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLvoid * data);
*/
float mi = 1e20, ma = -1e20;
// format = GL_RED, type = GL_FLOAT
//window->clear();
//window->draw(sprite_broughtback);
if (false) {
if (whole_size*whole_size < 4096)
{
//glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, values);
//glReadPixels(0, 0, whole_size, whole_size, GL_RED, GL_FLOAT, values);
}
Image brought_back;
brought_back.create(whole_size, whole_size, Color::Red);
for (int i = 0; i < whole_size; ++i) {
for (int j = 0; j < whole_size; ++j) {
ma = max(values[whole_size*i + j], ma);
mi = min(values[whole_size*i + j], mi);
}
}
msg(ma);
msg(mi);
}
//texture_broughtback.loadFromImage(brought_back);
rtext.create(whole_size, whole_size);
{
rtext.clear();
rtext.display();
rtext.draw(sprite_perlin, &perlin_shader);
sprite_rtext.setTexture(rtext.getTexture());
glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, values);
}
for (int i = 0; i < whole_size; ++i) {
for (int j = 0; j < whole_size; ++j) {
ma = max(values[whole_size*i + j], ma);
mi = min(values[whole_size*i + j], mi);
}
}
msg(ma);
msg(mi);
//img_back = rtext.getTexture().copyToImage();
//texture_broughtback.loadFromImage(img_back);
//sprite_broughtback.setTexture(texture_broughtback);
// scales and positions
sprite_broughtback.setScale(sprite_scale, sprite_scale);
sprite_rtext.setScale(sprite_scale, sprite_scale);
sprite_broughtback.move({ 0,labground::wincenter.y });
sprite_rtext.move({ labground::wincenter.x,0 });
auto error = glGetError();
msg(error);
}
void init() {
grad_size = 20;
grad_quant = 4;
whole_size = grad_size * (grad_quant - 1);
if (grad_quant*grad_quant > 4096) { msg("can't send gradients, please allocate a large C-type array in the code below!"); return; }
{
int seed = 43123;
auto rand_v = seeded_rand_vec2(seed, grad_quant*grad_quant);
for (int i = 0; i < grad_quant*grad_quant; ++i) {
gradients_ctype[i] = 2.0f*rand_v[i] - Vec2{ 1.f, 1.0f };
}
}
msg(grad_size);
msg(grad_quant);
msg(whole_size);
auto smallest_size = min(labground:: windowsize.x, labground::windowsize.y);
sprite_scale = 0.5f* smallest_size / whole_size;
init_perlin();
pull_data();
}
void draw(RenderTarget * target) {
//target->draw(sprite_perlin, &perlin_shader);
target->draw(sprite_perlin, &perlin_shader);
target->draw(sprite_broughtback);
target->draw(sprite_rtext);
}
void mouse_moved(Vec2 mpos_abs) {
auto pixel = ivec2(mpos_abs / sprite_scale);
pixel.x = max(0, min(whole_size - 1, pixel.x));
pixel.y = max(0, min(whole_size - 1, pixel.y));
}
}
// treating SFML events
void mouse_moved(Vec2 pos) {
};
void mouse_click (sf::Mouse::Button button) {
};
void mouse_release (sf::Mouse::Button button) {
if (button == Mouse::Button::Left) {
}
};
void treat_other_event (Event&e) {
if (e.type == Event::MouseWheelMoved && e.mouseWheel.delta){
labground::zoom(e);
}
};
void treat_key_event(Keyboard::Key k) {
switch (k)
{
case Keyboard::E:
break;
case Keyboard::I:
break;
case Keyboard::Q:
break;
case Keyboard::BackSpace:
break;
case Keyboard::Space:
break;
case Keyboard::S:
break;
case Keyboard::Num1:
break;
case Keyboard::Num2:
case Keyboard::Num3:
case Keyboard::Num4:
case Keyboard::Num5:
break;
}
};
#include <SFML\Window\ContextSettings.hpp>
// initializing the window
void init_window() {
using namespace labground;
Vec2i screen_resolution = { int(VideoMode::getDesktopMode().width), int(VideoMode::getDesktopMode().height) };
windowsize = Vec2i(0.5f*screen_resolution.x, 0.9f*screen_resolution.y);
//winsize = Vec2(windowsize);
wincenter = 0.5f*Vec2(windowsize);
// placing the window on the desktop
Vec2i windowpos;
VideoMode::getDesktopMode().height;
windowpos = Vec2i(
screen_resolution.x - windowsize.x - 10,
screen_resolution.y - windowsize.y - 40
);
//auto opengl = cfg.getvar<Vec2i>("opengl");
// ContextSettings::Core
//ContextSettings settings(0, 0, 0, 4, 5);
ContextSettings settings(0, 0, 0, 3, 0);
//sf::RenderWindow window(sf::VideoMode(windowsize.x, windowsize.y), "perlin shader");
window = new sf::RenderWindow(sf::VideoMode(windowsize.x, windowsize.y), "perlin shader", 7, settings);
window->setFramerateLimit(60);
//frame_duration = 1.0f / 60;
window->setPosition(windowpos);
ui_view = view = window->getDefaultView();
}
void draw() {
using namespace labground;
window->setView(view);
//////////////// OBJECTS THAT CAN BE ZOOMED ////////////////
perlin_shading::draw(window);
//////////////// OBJECTS THAT CANNOT BE ZOOMED ////////////////
window->setView(ui_view);
}
void loop() {
using namespace labground;
while (window->isOpen())
{
sf::Event event;
while (window->pollEvent(event))
{
switch (event.type)
{
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::Escape)
window->close();
treat_key_event(event.key.code);
break;
case sf::Event::Closed:
window->close();
break;
case sf::Event::MouseButtonPressed:
mouse_click(event.mouseButton.button);
break;
case sf::Event::MouseButtonReleased:
mouse_release(event.mouseButton.button);
break;
case sf::Event::MouseMoved:
mpos = Vec2(event.mouseMove.x, event.mouseMove.y);
mpos_abs = window->mapPixelToCoords(Vec2i(mpos), view);
mouse_moved(mpos);
break;
default:
treat_other_event(event);
break;
}
}
window->clear(Color(16,16,16));
//update();
draw();
window->display();
}
}
int main(int argc, char*argv[]) {
init_window();
perlin_shading::init();
loop();
}