Sign in to follow this  
ErekT

GLSL: read from source, write to different target

Recommended Posts

Hello community!

I've written a pixel art scaling filter for Blitzmax that I'm trying to convert into a glsl shader. The shader I've got so far "works" in that it seems to go through the algorithm as it's supposed to, but the problem is right now it writes to the same texture it reads from, where it's supposed to read from a source texture and then plop the calculated result into a different texture scaled to twice the size. It's probably trivial but I haven't been able to figure out how to set this up so far, so any pointers on how to get gl_fragcolor to write to a different texture would be great!


Here's the shader:

[vertex shader]

Quote:

uniform int T_width; // passed from bmax: texture width/height
uniform int T_height;

void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;

gl_Position = ftransform();
}



[fragment shader]

Quote:

uniform int T_width; // passed from bmax: texture width/height.
uniform int T_height;

float step_w = 1.0/T_width; // convert to texel 0.0 - 1.0 coordinates
float step_h = 1.0/T_height;

uniform sampler2D Texture0;
uniform sampler2D Texture1;

void main()
{
// set offsets from source pixel
vec2 offset_T = vec2(0, -step_h); // P plus (minus) offset_T equals T
vec2 offset_TR = vec2(step_w, -step_h);
vec2 offset_R = vec2(step_w, 0);
vec2 offset_BR = vec2(step_w, step_h);
vec2 offset_B = vec2(0, step_h);
vec2 offset_BL = vec2(-step_w, step_h);
vec2 offset_L = vec2(-step_w, 0);
vec2 offset_TL = vec2(-step_w, -step_h);

// P is the pixel to read from
// P_1 to P_4 represent the four output pixels, defaults to source
// T, L, R, B are short for Top, Left, Right and Bottom (of the source pixel)
// TL means Top Left corner, BR bottom right corner etc...
vec4 P = texture2D(Texture0, gl_TexCoord[0].st);
vec4 P_1 = texture2D(Texture0, gl_TexCoord[0].st);
vec4 P_2 = texture2D(Texture0, gl_TexCoord[0].st);
vec4 P_3 = texture2D(Texture0, gl_TexCoord[0].st);
vec4 P_4 = texture2D(Texture0, gl_TexCoord[0].st);
vec4 T = texture2D(Texture0, gl_TexCoord[0].xy + offset_T);
vec4 TR = texture2D(Texture0, gl_TexCoord[0].xy + offset_TR);
vec4 R = texture2D(Texture0, gl_TexCoord[0].xy + offset_R);
vec4 BR = texture2D(Texture0, gl_TexCoord[0].xy + offset_BR);
vec4 B = texture2D(Texture0, gl_TexCoord[0].xy + offset_B);
vec4 BL = texture2D(Texture0, gl_TexCoord[0].xy + offset_BL);
vec4 L = texture2D(Texture0, gl_TexCoord[0].xy + offset_L);
vec4 TL = texture2D(Texture0, gl_TexCoord[0].xy + offset_TL);

// check pixels surrounding P and set output pixels according
// to their values
if (T != B && L != R)
{
if (T == L && P != TL) { P_1 = L; }
if (T == R && P != TR) { P_2 = T; }
if (L == B && P != BL) { P_3 = B; }
if (R == B && P != BR) { P_4 = R; }
}

// get current frag position
int modt = mod((gl_TexCoord[1].x*T_width), 2);
int mods = mod((gl_TexCoord[1].y*T_height), 2);

// set P to one of the output pixels according to where
// current fragment position is at
if (modt == 0 && mods == 0) { P = P_1; }
if (modt == 1 && mods == 0) { P = P_2; }
if (modt == 0 && mods == 1) { P = P_3; }
if (modt == 1 && mods == 1) { P = P_4; }

gl_FragColor = P;
}


[Edited by - ErekT on December 8, 2010 9:11:48 AM]

Share this post


Link to post
Share on other sites
Do you have a custom framebuffer target? What's your opengl client code look like?

You should have some combination of glBindFramebuffer()/glFramebufferTexture2D() if you want to render to a texture.

Share this post


Link to post
Share on other sites
Thanks for the reply :)

Err, I have no custom framebuffer target actually. I assumed passing both texture ID's to the shader with glUniform1iARB would do the trick. The code I use for calling the textures and activating the shader is below. NB: it's in blitzmax syntax (BASIC language) so no curly brackets or semi-colons. Wend is part of the "While" loop syntax and po.Activate()/DeActivate() are wrapper functions for glUseProgramObjectARB().

Quote:

po.Activate()
po.SetUI1("T_width", Tex0_X)
po.SetUI1("T_height", Tex0_Y)
po.SetUI1("Texture0", Tex0) //' = glUniform1iARB(Tex0,0)
po.SetUI1("Texture1", Tex1)

glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, Tex0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

glActiveTexture(GL_TEXTURE1)
glBindTexture(GL_TEXTURE_2D, Tex1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

glBegin GL_QUADS
glTexCoord2f (0.0, 0.0)
glVertex3f (-2.2, -2.2, 0.0)
glTexCoord2f (1.0, 0.0)
glVertex3f (2.2, -2.2, 0.0)
glTexCoord2f (1.0, 1.0)
glVertex3f (2.2, 2.2, 0.0)
glTexCoord2f (0.0, 1.0)
glVertex3f (-2.2, 2.2, 0.0)
glEnd();

po.DeActivate()

Flip
Wend



I'll read up on glBindFramebuffer() and glFramebufferTexture2D() and see if I can implement them. Urk, this OpenGL programming business has been a real horror so far! I really appreciate the help :)

Share this post


Link to post
Share on other sites
Quote:
but the problem is right now it writes to the same texture it reads from

No it doesn't. It is possible, but the results are undefined. What you are doing looks like you are rendering to the screen buffer. As karwosts said, you want FramebufferObjects.

Btw:

po.SetUI1("Texture0", Tex0) //' = glUniform1iARB(Tex0,0)
po.SetUI1("Texture1", Tex1)

I think that is supposed to be

po.SetUI1("Texture0", 0) //' = glUniform1iARB(Tex0,0)
po.SetUI1("Texture1", 1)

Share this post


Link to post
Share on other sites
Could you elaborate some on how to use these FBO's? I've been trying to stick this code:

Quote:

Global fbo:int // bmax for global integer fbo

glGenFramebuffers(1, Varptr fbo)
glBindFramebuffer(GL_FRAMEBUFFER, fbo)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE2D, Tex1, 0)
glBindFramebuffer(GL_FRAMEBUFFER, 0)



... pretty much anywhere in my code without any other result than getting an all-black screen. I'm coming close to attacking my computer at this point. Marone mia!

Problem is, I'm pretty fresh at OpenGL programming and not at all steady on how to link textures, framebuffers and the whatnot up with uniforms the shader can read. Or how to get the shader to write to a designated framebuffer for that matter. Gah! Maybe I'd best go back to the warm and fluffy world of Blitzmax programming before I go completely ape.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this