Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - SuperApe

Pages: [1] 2
1
General / Re: Check if hovering over a visible part of a sprite
« on: June 02, 2020, 12:13:21 am »
I totally just did this for my project. A hover behavior looks nice. Maybe I can help.

I'm trying to work on a ui library for my game, and I need to make sure that the buttons are not under other objects, to invoke their events. Any way I can go about this?
What your describing sounds like "consuming click / hover events". Yeah? You want to make sure the button behavior is the only effect of the cursor, while underlying objects that may react to the cursor do not react while the button takes over. Do I have that right?

As you may already guess, hover behavior is a function of comparing the mouse position to the bounds of the button sprite. This is fairly straightforward, so I'm guessing the part you're asking about is more, "how do I stop things behind the button level from being hovered/clicked, etc?"

If that's the real question, here's how I solved that. There's more than two or three states to my clickable buttons. They (and all UI Elements in my system) have Disabled, Normal, Hover and Active. (I actually use an enum, and use this to manage drawing as well as behavior with regard to mouse / cursor input)

So, a Disabled button (or other element that takes a hover or click) simply ignores the cursor, I just bypass behavior altogether, and draw semi-transparent on draw. A Normal button, however, _can_ accept the cursor position as to switch to Hover state, a click at that point to Active state.

And then, the trick is to manage the states of the underlying buttons and hover-able objects. In other words, there will be those UI buttons that are active as within one dialog box or UI panel, while those under are switched to a Disabled state while this set of buttons is visible. (incidentally, my system also makes use of visible and active states to use in bypassing update and draw methods)

If what you're asking is, "Can SFML just detect if the sprite is drawn but covered up by another button, so it doesn't consume a hover or click?", I'm saying, the answer is likely no, and I made that behavior myself, just managing which levels of interactive buttons are Disabled, and which are not.

'Hope that helps.


2
General / Re: linking issue : Undefined Reference to `_Unwind_Resume'
« on: June 02, 2020, 12:01:26 am »
(pls excuse bumping old thread again, but this matches close to a current issue)

Another option that always works is to simply compile SFML yourself, using your chosen compiler. Then it's guaranteed to be compatible with the executables you produce.
This totally makes sense, and it is why I downloaded source, configured cmake-gui to create a CodeBlocks project for SFML locally, and built "all" with all configurations I use (dynamic and static, debug and release).

After completing SFML build results, and moving the appropriate .dlls and .a files for use with my CodeBlocks project, I got the linker error described above - related to
libsfml-graphics-s.a(Sprite.cpp.obj):Sprite.cpp

So, thinking perhaps I'm working with the wrong compiler (MinGW as CodeBlocks 20.03 provides, instead of mingw32, as I had been using previously with CodeBlocks 17.02). After rebuilding SFML using the compiler directory CodeBlocks provides (MinGW - I see both SJLJ and DW2 there), and replacing the .a and .dlls, I got the same linker error.

Doing a bit more reading into this error, it seems just a .dll mismatch, but if I just built it, as Jesper says, shouldn't this just work? CodeBlocks does have settings to point to the correct compiler, and for 'auto-detecting' it. It does auto-configure to CodeBlocks' MinGW.

What would be a good next step here? This setup seemed a little more touchy, less smooth, with the new version of CodeBlocks install. (that's where the linking issues began)

Ideas?

(linker error results, pls excuse relative path to 32-bit install within CodeBlocks)

||=== Build: Release in AwesomeSecretProjectName (compiler: GNU GCC Compiler) ===|
..\..\..\..\..\..\Program Files (x86)\CodeBlocks\SFML-2.5.1\lib\libsfml-graphics-s.a(Sprite.cpp.obj):Sprite.cpp|| undefined reference to `_Unwind_Resume'|
..\..\..\..\..\..\Program Files (x86)\CodeBlocks\SFML-2.5.1\lib\libsfml-graphics-s.a(Sprite.cpp.obj):Sprite.cpp|| undefined reference to `_Unwind_Resume'
|
..\..\..\..\..\..\Program Files (x86)\CodeBlocks\SFML-2.5.1\lib\libsfml-graphics-s.a(Sprite.cpp.obj):Sprite.cpp|| undefined reference to `_Unwind_Resume'|
||error: ld returned 1 exit status|
||=== Build failed: 4 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

3
The "help" I'm looking for is really a request to double-check I used SFML as it was intended to be used for my case, and then the request would be to make this clearer in the documentation in one or two places, if so.

I post this as I have just gotten all to work as expected / intended, but the route to get here was painful, so I'm hoping to see changes to documentation that help others in a similar situation.

The subject is using the static Listener and setting properties on Sound object instances to achieve spatial audio in a 2D environment, where the Listener is to match the View position, and sounds would therefore really only register as "to the left" or "to the right" in relation to the center of the view, with proper attenuation.

All audio used is mono, so spatial audio is possible. Some of the audio used in the project is not meant to be spatial (music, ui sfx) and so there are different configurations that were needed.

References used in this effort include the SoundSource doc https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1SoundSource.php and static Listener doc https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1Listener.php.

Additionally, the Spatialization tutorial https://www.sfml-dev.org/tutorials/2.5/audio-spatialization.php and then this forum thread https://en.sfml-dev.org/forums/index.php?topic=14566.0 helped to highlight where I was having problems understanding the API intent, so ultimately it helps to reference all these.

With all that said, and understanding that we're all careful, we (largely) read documentation before making assumptions, and we (largely) make mistakes from time to time, worthy of improvement, I humbly suggest we revisit how this kind of effort is documented. There are a couple of things to point out in terms of how the documentation presents the tools available.

The Spatialization tutorial says this:
Quote
(in General) By default, sounds and music are played at full volume in each speaker; they are not spatialized. ... (for Audio Sources) The main property is the position of the audio source. ... This position is absolute by default, but it can be relative to the listener if needed. ... This can be useful for sounds emitted by the listener itself (like a gun shot, or foot steps). It also has the interesting side-effect of disabling spatialization if you set the position of the audio source to (0, 0, 0). Non-spatialized sounds can be required in various situations: GUI sounds (clicks), ambient music, etc.
The concern here is simply that the sound results are defined in two states: absolute and relative (to listener); however if you read this carefully, you are hearing "default = absolute = full volume both speakers" and then "relative = emitted by listener itself = examples: foot steps, gui sounds, ambient music". Which, are actually describing the same results: full volume both speakers. This could be carefully cleaned up in the documentation to avoid confusion by clearly defining two states of the sound source: absolute and relative.

I suggest that without clearing it up, absolute sound by default apparently means the sound seems emitted at the listener location. But that conflicts with what the SoundSource class documentation has to say:
Quote
void sf::SoundSource::setRelativeToListener(bool relative)   
Make the sound's position relative to the listener or absolute.

Making a sound relative to the listener will ensure that it will always be played the same way regardless of the position of the listener. This can be useful for non-spatialized sounds, sounds that are produced by the listener, or sounds attached to it. The default value is false (position is absolute).

Parameters
relative   True to set the position relative, false to set it absolute
Here is where the solution to my particular setup fell into place, but only by realizing that the word "relative", as in, "this sound source position relative to the listener position", actually is used in an inverse meaning. Based on the explanation, rather than the word "relative", it was clear what was meant is the SoundSource position will seem as if it is following the Listener position, as if it is the same position as the Listener with no difference, no delta.

"Relative", I'm suggesting, actually infers a difference between two, with a delta that in this case would make sense for spatialization. In other words, if a sound is relative to the listener, the suggested meaning is that this enables spatialization between sound and listener. But in practice, the opposite is true.

So I'm suggesting a) the word "relative" was used in a misleading way (if not opposite), and b) the description of the results called for with relative = true matches what the Spatialization tutorial says is already default (absolute) behavior; in other words, this documentation again conflicts.

That was my first point, the use of the word "relative" in the method name, property name conflicts with the actual results. My suggestion is documentation can call this out more clearly, and help others in the future. (I'm not suggesting you change the API to fit the language, I know that's too much to ask at this point)

The second point has to do with the practical use for spatialization of audio in 2D, and without a clear example, the development was more painful than necessary, and a short example in the documentation would be excellent. So this calls for another sanity check: did I do this as the API expects I would, because it seemed as intuitive as I could get it.

Again, there is a brief mention in the Spatialization tutorial
Quote
If you have a 2D world you can just use the same Y value everywhere, usually 0.
So, to be honest, that threw me off for a while. Converting my moving view center position to (x, 0, y) for the 3D vector needed by the listener was not intuitive and did not yield expected results. And setting SourceSource locations to match this space was tried in many different attempts to follow this guidance. All this didn't turn out to be necessary in the end.

In fact, here is what worked:
    sf::Listener::setDirection(0.f,0.f,-1.f);
    sf::Listener::setUpVector(0.f,1.f,0.f);
    while (gameLoop) {
        sf::Listener::setPosition( myView.getCenter().x, myView.getCenter().y, 0.f );
    }
This configuration is what worked for a simple 2D view game, where the view travels with my local player in the x,y 2D space, and all sound emitting objects likewise live on the same x,y 2D space. So, when a sound object was set for spatialization the position was set as
    mySound.setRelativeToListener(false);
    mySound.setMinDistance(50.f);
    mySound.setAttenuation(0.1f);
    mySound.setPosition(sPos.x,sPos.y,0.f);
(Individual configurations for minDistance and Attenuation will vary) But, notice two things here: first, the space is simply using z=0, with x & y the same, and second, to make this spatialized, the sound is set to be absolute, not relative (opposite meaning of "relative to listener"). And, following this new understanding, the non-attenuated / non-spatialized sounds needed for this project are defined like this:
    mySound.setPosition(0.f,0.f,0.f);
    mySound.setRelativeToListener(true);
    mySound.setMinDistance(1.f);
    mySound.setAttenuation(1.f);
(while the position, minDistance and Attenuation are irrelevant if not spatialized, I set it this way for tidy-ness)

So, my second point is: This clear example, with a 1 to 1 relationship to the 2D visual space a simple project works in, would be so helpful to have in the documentation, and it would have saved a lot of time. Clearing up the "y=0" idea, as well, would be helpful, as that was not the intuitive way to go.

The results with the above example are as one would expect of a simple 2D audio space. Sounds from the left are heard on the left, etc. Note the direction of the Listener is pointing to negative Z. Up vector is positive Y. And all positions are using the 2D space with a Z of zero.

With all this, I'm hoping the two points are well taken in the spirit of making the documentation better for the next person.
  • All documentation surrounding relativity to listener ("isRelativeToListener", "setRelativeToListener", etc) needs clarification to ensure the reader understands the two states of the sound: absolute means it lives in a spatialized sound space, and the listener position will matter (even if default is origin and if you do nothing to the listener, it will play at full volume in both speakers), while relative actually means the sound will emit from the listener regardless of its position or the sound source position, and will always play at full volume in both speakers.
  • A clear example for a simple 2D spatialized audio setup would be extremely helpful. Translate sound positions to 3D sound space for listener as (x,y,0) and position listener likewise as (x,y,0). Set direction of listener to point toward negative Z. Set up vector for listener to positive Y.
[EDIT:]Correction as noted in my reply below:
Quote
of course instead it would make a lot more sense to leave orientation aligned with the 'default' 2D world as up vector -Y and facing direction +Z

I do hope that helps. And of course, if I've misunderstood any/all this, I think that also helpful to be corrected.

(love SFML btw, thanks!)

4
All good information, and I appreciate the responses. The analogy makes sense, and helps to make clear the names used.

'Just for those keeping score at home: an even simpler (and kind of obvious) setup with regard to Listener orientation is _not_ up vector +Y and facing direction -Z, of course instead it would make a lot more sense to leave orientation aligned with the 'default' 2D world as up vector -Y and facing direction +Z. (that is, in our 2D default orientation using 'top' and 'height', negative Y is up; and so positive Z can remain forward)

(I realized this small point a little after posting, and sry I come from a 3D background with positive Y up and just forgot to make that point clearer until now)

5
I also encountered this, so I'm glad the topic was available to browse.

It came up after updating my IDE (CodeBlocks) to the latest, which seemed to also update the compiler version.

'Going through the steps to get the dll to match the compiler again. (perhaps to compile SFML, see if just grabbing latest SFML release will be enough)

6
The "help" I'm looking for is really a request to double-check I used SFML as it was intended to be used for my case, and then the request would be to make this clearer in the documentation in one or two places, if so.

I post this as I have just gotten all to work as expected / intended, but the route to get here was painful, so I'm hoping to see changes to documentation that help others in a similar situation.

The subject is using the static Listener and setting properties on Sound object instances to achieve spatial audio in a 2D environment, where the Listener is to match the View position, and sounds would therefore really only register as "to the left" or "to the right" in relation to the center of the view, with proper attenuation.

All audio used is mono, so spatial audio is possible. Some of the audio used in the project is not meant to be spatial (music, ui sfx) and so there are different configurations that were needed.

References used in this effort include the SoundSource doc https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1SoundSource.php and static Listener doc https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1Listener.php.

Additionally, the Spatialization tutorial https://www.sfml-dev.org/tutorials/2.5/audio-spatialization.php and then this forum thread https://en.sfml-dev.org/forums/index.php?topic=14566.0 helped to highlight where I was having problems understanding the API intent, so ultimately it helps to reference all these.

With all that said, and understanding that we're all careful, we (largely) read documentation before making assumptions, and we (largely) make mistakes from time to time, worthy of improvement, I humbly suggest we revisit how this kind of effort is documented. There are a couple of things to point out in terms of how the documentation presents the tools available.

The Spatialization tutorial says this:
Quote
(in General) By default, sounds and music are played at full volume in each speaker; they are not spatialized. ... (for Audio Sources) The main property is the position of the audio source. ... This position is absolute by default, but it can be relative to the listener if needed. ... This can be useful for sounds emitted by the listener itself (like a gun shot, or foot steps). It also has the interesting side-effect of disabling spatialization if you set the position of the audio source to (0, 0, 0). Non-spatialized sounds can be required in various situations: GUI sounds (clicks), ambient music, etc.
The concern here is simply that the sound results are defined in two states: absolute and relative (to listener); however if you read this carefully, you are hearing "default = absolute = full volume both speakers" and then "relative = emitted by listener itself = examples: foot steps, gui sounds, ambient music". Which, are actually describing the same results: full volume both speakers. This could be carefully cleaned up in the documentation to avoid confusion by clearly defining two states of the sound source: absolute and relative.

I suggest that without clearing it up, absolute sound by default apparently means the sound seems emitted at the listener location. But that conflicts with what the SoundSource class documentation has to say:
Quote
void sf::SoundSource::setRelativeToListener(bool relative)   
Make the sound's position relative to the listener or absolute.

Making a sound relative to the listener will ensure that it will always be played the same way regardless of the position of the listener. This can be useful for non-spatialized sounds, sounds that are produced by the listener, or sounds attached to it. The default value is false (position is absolute).

Parameters
relative   True to set the position relative, false to set it absolute
Here is where the solution to my particular setup fell into place, but only by realizing that the word "relative", as in, "this sound source position relative to the listener position", actually is used in an inverse meaning. Based on the explanation, rather than the word "relative", it was clear what was meant is the SoundSource position will seem as if it is following the Listener position, as if it is the same position as the Listener with no difference, no delta.

"Relative", I'm suggesting, actually infers a difference between two, with a delta that in this case would make sense for spatialization. In other words, if a sound is relative to the listener, the suggested meaning is that this enables spatialization between sound and listener. But in practice, the opposite is true.

So I'm suggesting a) the word "relative" was used in a misleading way (if not opposite), and b) the description of the results called for with relative = true matches what the Spatialization tutorial says is already default (absolute) behavior; in other words, this documentation again conflicts.

That was my first point, the use of the word "relative" in the method name, property name conflicts with the actual results. My suggestion is documentation can call this out more clearly, and help others in the future. (I'm not suggesting you change the API to fit the language, I know that's too much to ask at this point)

The second point has to do with the practical use for spatialization of audio in 2D, and without a clear example, the development was more painful than necessary, and a short example in the documentation would be excellent. So this calls for another sanity check: did I do this as the API expects I would, because it seemed as intuitive as I could get it.

Again, there is a brief mention in the Spatialization tutorial
Quote
If you have a 2D world you can just use the same Y value everywhere, usually 0.
So, to be honest, that threw me off for a while. Converting my moving view center position to (x, 0, y) for the 3D vector needed by the listener was not intuitive and did not yield expected results. And setting SourceSource locations to match this space was tried in many different attempts to follow this guidance. All this didn't turn out to be necessary in the end.

In fact, here is what worked:
    sf::Listener::setDirection(0.f,0.f,-1.f);
    sf::Listener::setUpVector(0.f,1.f,0.f);
    while (gameLoop) {
        sf::Listener::setPosition( myView.getCenter().x, myView.getCenter().y, 0.f );
    }
This configuration is what worked for a simple 2D view game, where the view travels with my local player in the x,y 2D space, and all sound emitting objects likewise live on the same x,y 2D space. So, when a sound object was set for spatialization the position was set as
    mySound.setRelativeToListener(false);
    mySound.setMinDistance(50.f);
    mySound.setAttenuation(0.1f);
    mySound.setPosition(sPos.x,sPos.y,0.f);
(Individual configurations for minDistance and Attenuation will vary) But, notice two things here: first, the space is simply using z=0, with x & y the same, and second, to make this spatialized, the sound is set to be absolute, not relative (opposite meaning of "relative to listener"). And, following this new understanding, the non-attenuated / non-spatialized sounds needed for this project are defined like this:
    mySound.setPosition(0.f,0.f,0.f);
    mySound.setRelativeToListener(true);
    mySound.setMinDistance(1.f);
    mySound.setAttenuation(1.f);
(while the position, minDistance and Attenuation are irrelevant if not spatialized, I set it this way for tidy-ness)

So, my second point is: This clear example, with a 1 to 1 relationship to the 2D visual space a simple project works in, would be so helpful to have in the documentation, and it would have saved a lot of time. Clearing up the "y=0" idea, as well, would be helpful, as that was not the intuitive way to go.

The results with the above example are as one would expect of a simple 2D audio space. Sounds from the left are heard on the left, etc. Note the direction of the Listener is pointing to negative Z. Up vector is positive Y. And all positions are using the 2D space with a Z of zero.

With all this, I'm hoping the two points are well taken in the spirit of making the documentation better for the next person.
  • All documentation surrounding relativity to listener ("isRelativeToListener", "setRelativeToListener", etc) needs clarification to ensure the reader understands the two states of the sound: absolute means it lives in a spatialized sound space, and the listener position will matter (even if default is origin and if you do nothing to the listener, it will play at full volume in both speakers), while relative actually means the sound will emit from the listener regardless of its position or the sound source position, and will always play at full volume in both speakers.
  • A clear example for a simple 2D spatialized audio setup would be extremely helpful. Translate sound positions to 3D sound space for listener as (x,y,0) and position listener likewise as (x,y,0). Set direction of listener to point toward negative Z. Set up vector for listener to positive Y.
I do hope that helps. And of course, if I've misunderstood any/all this, I think that also helpful to be corrected.

(love SFML btw, thanks!)

7
SFML game jam / Re: Revival attempt
« on: May 21, 2020, 11:21:41 pm »
Perhaps with a little scheduling ahead (I'm busy with a project atm, not sure about others) and especially a little marketing to draw attention, it may get traction. Without those, it would be lucky to find takers at the last minute.

/my $0.02

8
Super big thank you, Hapax and Laurent! This is helpful.

(I appreciate the sanity check, Hapax. A result of what I was going for is now displayed on the screenshot thread)

I now have a good set of things to try and chase down, Laurent, thank you. First, my sneaking suspicion is that if I weren't using Code::Blocks (VS instead), the output would be clearly displayed. (maybe) But, this is a new set of things to try and they will help me improve my debugging workflow. 'Very much appreciated!  :D

9
SFML projects / ubiquitous 2-D Tank development
« on: April 05, 2020, 06:01:08 pm »
With help from Hapax to jump start GLSL.  :)

Tank prototype started last month includes audio, tank mechanics, vfx (custom particle system), and endless terrain using image-based noise blending. Maybe I could start a project thread once this has a game scene class, menu system, and at least a level.

(Pleased there are still members sharing work here)  :D


10
Now that shaders load (and _why_ no output errors?), I see something that causes my fancy GLSL file to fail.

#version 330 core

So, with that commented out, I actually see stuff blending with a loaded shader file, and I think I can work things out from here.

To sum up the original issue: it looks like I'm not seeing (have not seen) output from SFML complaining about the loading attempts; just failed to load until I tried in this separate test. But, for sure, adding #version causes SFML to bork.

[EDIT] Best guess is (based on what changed to make loading possible) the fixes to the floats being set to uniforms was the only issue for loading. Additionally, "#version..." caused loading to fail. No compile error output to be found in any console windows. (shrug) On the plus side, with shader loading working, I was able to get my fancy GLSL blending working as designed, so it was good practice. Thank you, Hapax! Thanks for your patience. :D

11
Creating a separate version was a good idea. Compiled and got a loaded shader (from memory), and saw something I think you said.

                    pixelAlpha.a = texMgr.texMaskNoise.copyToImage().getPixel(getX, getY).a;
                    float centerA = (float)(pixelAlpha.a/255);
                    tileBlend.setUniform("tileAlphaCenter", centerA);
...wasn't going to work, and the results showed alpha clipping to either full or not.

Corrected to:
                    pixelAlpha.a = texMgr.texMaskNoise.copyToImage().getPixel(getX, getY).a;
                    float centerA = (pixelAlpha.a/255.f);
                    tileBlend.setUniform("tileAlphaCenter", centerA);

So, I was able to migrate that fix throughout the fancy stuff, and fix at least one issue: passing floats that weren't floats. Okay, with the shader loaded in this version, I can now focus on what might be wrong loading GLSL from file. (first, I'll check paths again, then focus on the GLSL)

12
I hope this is complete enough to review. It's not elegant of course:

#include <math.h>
#include <cmath>
#include <string>

#include <SFML/Graphics.hpp>
#include <SFML/Window/VideoMode.hpp>
#include <SFML/Audio.hpp>

// from headers --
sf::Font titleFont, headingFont, textFont;
bool FontInit() {
    bool loadFontOkay = true;
    if ( !titleFont.loadFromFile("image/fontTitle.ttf") ||
            !headingFont.loadFromFile("image/fontHeading.ttf") ||
            !textFont.loadFromFile("image/fontText.ttf") ) {
        // error
        loadFontOkay = false;
    }
    return loadFontOkay;
}

sf::IntRect texSize = sf::IntRect(0, 0, 32, 32);

class TextureManager {
public:
    sf::Texture texMaskNoise;
    TextureManager() { MaskTextureInit(); }
private:
    void MaskTextureInit()
    {
        texMaskNoise.loadFromFile("image/Mask_Noise.png", texSize);
    }
};

static TextureManager texMgr;
// -- end from headers

// C++, SFML, OpenGL

int main()
{
    // rand seed
    srand(time(NULL));

    // main game setup //

    // window
    sf::RenderWindow rWin( sf::VideoMode( 1024, 576, 256 ), "X" );
    sf::VideoMode vm( sf::VideoMode::getDesktopMode() );
    rWin.setPosition( sf::Vector2i( (( vm.width / 2 ) - 512 ) , (( vm.height / 2 ) - 320 ) ) );

    // time and space
    sf::Clock frameTimer;
    frameTimer.restart();
    float timeDelta = 0.f;
    float globalTime = 1.f;
    float globalScale = 2.f;

    // view port
    sf::View vw;
    vw.setSize(1024.f, 576.f);
    vw.setViewport(sf::FloatRect(0.f, 0.f, 1.f, 1.f));
    vw.setCenter(320.f, 320.f);

    // terrain
    // TODO: implement terrain manager
    // holds all terrain textures + noise mask
    // uses terrain layer offsets from custom Scene class
    // handles render texture + tile blend shader
    // scrolls with offset to draw tiles in view, based on player position, with updated render texture center
    // 10x10 tiles = 320x320 pixels
    // 32x32 tiles = 1024x1024 pixels
    sf::Texture tTexture;
    if ( !tTexture.loadFromFile("image/Terrain_Soil_Base.png", sf::IntRect(0,0,32,32) ) )
    {
        // error
    }
    tTexture.setRepeated(true);
    tTexture.setSmooth(false);
    sf::Sprite terrain;
    terrain.setTexture(tTexture);
    terrain.setTextureRect(sf::IntRect(0, 0, 32 * 10, 32 * 10));
    terrain.setOrigin(160.f, 160.f);
    terrain.setScale(globalScale, globalScale);
    terrain.setPosition(320.f, 320.f);

    // terrain layer prototype
    sf::RenderTexture terrainGrassLayer;
    sf::ContextSettings settings;
    settings.depthBits = 8;
    terrainGrassLayer.create( 32 * 10 * globalScale, 32 * 10 * globalScale, settings );

    sf::Texture lTexture;
    if ( !lTexture.loadFromFile("image/Terrain_Soil_Grass.png", sf::IntRect(0,0,32,32) ) )
    {
        // error
    }
    tTexture.setRepeated(true);
    tTexture.setSmooth(false);
    sf::Sprite terrainLayer;
    terrainLayer.setTexture(lTexture);
    terrainLayer.setTextureRect(sf::IntRect(0,0,32,32));
    terrainLayer.setOrigin(160.f, 160.f);
    terrainLayer.setScale(globalScale, globalScale);
    terrainLayer.setPosition(320.f, 320.f);

    terrainGrassLayer.draw( terrain );
    // find all 1024 alpha values of the noise mask texture pixels, use them to set alpha of each layer 32x32 tile
    // TODO: store these values instead of continually reading from image file

    // attempt to load shader
    // FIXME: shaders are available, but failing to load, either from src/ or image/
    sf::Shader tileBlend;
    //bool shaderLoaded = tileBlend.loadFromFile( "src/TerrainTest.glsl", sf::Shader::Fragment );
    //bool shaderLoaded = tileBlend.loadFromFile( "src/TerrainTileBlend.glsl", sf::Shader::Fragment );

    const std::string vertexShader = \
    "void main()" \
    "{" \
    "   // transform the vertex position" \
    "   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" \
    "" \
    "   // transform the texture coordinates" \
    "   gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;" \
    "" \
    "   // forward the vertex color" \
    "   gl_FrontColor = gl_Color;" \
    "}";
    const std::string fragmentShader = \
    "uniform sampler2D tSample;" \
    "uniform float tileAlphaCenter;" \
    "void main()" \
    "{" \
    "    vec4 pixel = texture2D( tSample, gl_TexCoord[0].xy );" \
    "    pixel.a = tileAlphaCenter;" \
    "    gl_FragColor = gl_Color * pixel;" \
    "}";
    //bool shaderLoaded = tileBlend.loadFromMemory( vertexShader, fragmentShader );
    bool shaderLoaded = tileBlend.loadFromMemory( fragmentShader, sf::Shader::Fragment );

    std::string debugText = "";
    if ( sf::Shader::isAvailable() )
        debugText += "Shaders are available on this system";
    else
        debugText = "No shaders, sorry";

    /*
    // TEST FORCE COMPILATION ERROR MSG
    sf::Shader dummy;
    if ( !dummy.loadFromMemory("", sf::Shader::Fragment) )
    {
        debugText += "\n... dummy fails ...";
    }
    */


    for ( int t=0; t<5; t++ )
    {
        int offsetX, offsetY;
        offsetX = 0;
        offsetY = 0;
        switch (t)
        {
            case 0:
                lTexture.loadFromFile("image/Terrain_Soil_Rock.png", sf::IntRect(0,0,32,32) );
                break;
            case 1:
                lTexture.loadFromFile("image/Terrain_Soil_Root.png", sf::IntRect(0,0,32,32) );
                break;
            case 2:
                lTexture.loadFromFile("image/Terrain_Soil_Pebble.png", sf::IntRect(0,0,32,32) );
                break;
            case 3:
                lTexture.loadFromFile("image/Terrain_Soil_Grass.png", sf::IntRect(0,0,32,32) );
                break;
            case 4:
                lTexture.loadFromFile("image/Terrain_Soil_Flower.png", sf::IntRect(0,0,32,32) );
                break;
        }
        offsetX = (rand() % 32);
        offsetY = (rand() % 32);

        for ( int i=0; i<32; i++ )
        {
            for ( int n=0; n<32; n++ )
            {
                // TODO: migrate to function
                // TODO: allow function to return alpha value from pixel 'wrapped around' texture edge
                terrainLayer.setPosition( 320.f + (i * 32 * globalScale), 320.f + (n * 32 * globalScale) );
                sf::Color pixelAlpha = sf::Color::White;
                unsigned int getX, getY;
                getX = i + offsetX;
                getY = n + offsetY;
                if ( getX > 31 )
                    getX -= 31;
                if ( getY > 31 )
                    getY -= 31;
                pixelAlpha.a = texMgr.texMaskNoise.copyToImage().getPixel(getX, getY).a;

                if ( sf::Shader::isAvailable() && shaderLoaded )
                {
                    // blending across tile to surrounding eight mask pixel alpha values
                    // 1 2 3
                    // 4 X 5
                    // 6 7 8
                    // configure and utilize tileBlend shader
                    tileBlend.setUniform("tSample", lTexture);
                    pixelAlpha.a = texMgr.texMaskNoise.copyToImage().getPixel(getX, getY).a;
                    float centerA = (float)(pixelAlpha.a/255);
                    tileBlend.setUniform("tileAlphaCenter", centerA);

                    float topleftA = 0.f;
                    if ( getX > 0 && getY > 0 )
                    {
                        topleftA = (float)(texMgr.texMaskNoise.copyToImage().getPixel((getX-1),(getY-1)).a / 255);
                        topleftA += centerA;
                        topleftA /= 2.f;
                    }
                    else
                        topleftA = centerA;
                    float topA = 0.f;
                    if ( getY > 0 )
                    {
                        topA = (float)(texMgr.texMaskNoise.copyToImage().getPixel(getX,(getY-1)).a / 255);
                        topA += centerA;
                        topA /= 2.f;
                    }
                    else
                        topA = centerA;
                    float toprightA = 0.f;
                    if ( getX < 31 && getY > 0 )
                    {
                        toprightA = (float)(texMgr.texMaskNoise.copyToImage().getPixel((getX+1),(getY-1)).a / 255);
                        toprightA += centerA;
                        toprightA /= 2.f;
                    }
                    else
                        toprightA = centerA;
                    float leftA = 0.f;
                    if ( getX > 0 )
                    {
                        leftA = (float)(texMgr.texMaskNoise.copyToImage().getPixel((getX-1),getY).a / 255);
                        leftA += centerA;
                        leftA /= 2.f;
                    }
                    else
                        leftA = centerA;
                    float rightA = 0.f;
                    if ( getX < 31 )
                    {
                        rightA = (float)(texMgr.texMaskNoise.copyToImage().getPixel((getX+1),getY).a / 255);
                        rightA += centerA;
                        rightA /= 2.f;
                    }
                    else
                        rightA = centerA;
                    float bottomleftA = 0.f;
                    if ( getX > 0 && getY < 31 )
                    {
                        bottomleftA = (float)(texMgr.texMaskNoise.copyToImage().getPixel((getX-1),(getY+1)).a / 255);
                        bottomleftA += centerA;
                        bottomleftA /= 2.f;
                    }
                    else
                        bottomleftA = centerA;
                    float bottomA = 0.f;
                    if ( getY < 31 )
                    {
                        bottomA = (float)(texMgr.texMaskNoise.copyToImage().getPixel(getX,(getY+1)).a / 255);
                        bottomA += centerA;
                        bottomA /= 2.f;
                    }
                    else
                        bottomA = centerA;
                    float bottomrightA = 0.f;
                    if ( getX < 31 && getY < 31 )
                    {
                        bottomrightA = (float)(texMgr.texMaskNoise.copyToImage().getPixel((getX+1),(getY+1)).a / 255);
                        bottomrightA += centerA;
                        bottomrightA /= 2.f;
                    }
                    else
                        bottomrightA = centerA;
                    tileBlend.setUniform("tileAlphaTopLeft", topleftA);
                    tileBlend.setUniform("tileAlphaTop", topA);
                    tileBlend.setUniform("tileAlphaTopRight", toprightA);
                    tileBlend.setUniform("tileAlphaLeft", leftA);
                    tileBlend.setUniform("tileAlphaRight", rightA);
                    tileBlend.setUniform("tileAlphaBottomLeft", bottomleftA);
                    tileBlend.setUniform("tileAlphaBottom", bottomA);
                    tileBlend.setUniform("tileAlphaBottomRight", bottomrightA);
                    terrainGrassLayer.draw( terrainLayer, &tileBlend );
                }
                else
                {
                    // tile blend shader not found, just draw tile with tile center alpha value
                    terrainLayer.setColor( pixelAlpha );
                    terrainGrassLayer.draw( terrainLayer );
                }
            }
        }
    }
    if ( shaderLoaded )
        debugText += "\n... and shader loaded!";
    else
        debugText += "\n... and shader not loaded";

    terrainGrassLayer.display();
    sf::Sprite terrainLayerSprite;
    terrainLayerSprite.setTexture( terrainGrassLayer.getTexture() );

    // debug feedback
    sf::Text debugLine;
    debugLine.setFont(textFont);
    debugLine.setScale(.381f,.381f);
    debugLine.setPosition(32.f,48.f);

    // main loop
    rWin.setActive();
    rWin.setFramerateLimit(60);
    while ( rWin.isOpen() )
    {
        // time delta
        timeDelta = frameTimer.restart().asSeconds() * globalTime;

        // window events
        sf::Event event;
        while (rWin.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                rWin.close();
            if (event.type == sf::Event::Resized) {
                rWin.setSize( sf::Vector2u( 1024, 576 ) );
                rWin.setPosition( sf::Vector2i( (( vm.width / 2 ) - 512 ) , (( vm.height / 2 ) - 320 ) ) );
            }
        }

        // draw calls
        rWin.clear();
        rWin.setView( vw );
        rWin.draw( terrainLayerSprite );

        // debug
        debugLine.setString(debugText);
        if ( debugLine.getString() != "" )
            rWin.draw(debugLine);
        rWin.display();
    }
}
 

13
[EDIT: more complete version in next reply]

I understand. I tried to provide relevant code to the problem I've reduced it to: loadFromMemory and loadFromFile both return false.

If you think the problem is less about loadFromMemory or loadFromFile, I'm all ears.

I wish the problem were actually GLSL related, because I think I could work through that well enough. For example, if setting my float uniform wasn't working, and gave me a default zero value, I'd have a chance to see that with a hard-coded alpha value in GLSL for comparison.

Here's a little more complete version of the steps I'm taking after trying to load. (pls excuse breaking Demeter's law at this stage):

    sf::Shader tileBlend;
    //bool shaderLoaded = tileBlend.loadFromFile( "src/TerrainTest.glsl", sf::Shader::Fragment );
    //bool shaderLoaded = tileBlend.loadFromFile( "src/TerrainTileBlend.glsl", sf::Shader::Fragment );

    const std::string fragmentShader = \
    "uniform sampler2D tSample;" \
    "uniform float tileAlphaCenter;" \
    "void main()" \
    "{" \
    "    vec4 pixel = texture2D( tSample, gl_TexCoord[0].xy );" \
    "    pixel.a = tileAlphaCenter;" \
    "    gl_FragColor = gl_Color * pixel;" \
    "}";
    bool shaderLoaded = tileBlend.loadFromMemory( fragmentShader, sf::Shader::Fragment );
    ...
            // selection of the next terrain layer texture to draw as ltexture
            ...
                // getX and getY relate to pixel coordinates of a repeatable noise texture
                pixelAlpha.a = texMgr.texMaskNoise.copyToImage().getPixel(getX, getY).a;

                if ( sf::Shader::isAvailable() && shaderLoaded )
                {
                    // blending across tile to surrounding eight mask pixel alpha values
                    // 1 2 3
                    // 4 X 5
                    // 6 7 8
                    // configure and utilize tileBlend shader
                    tileBlend.setUniform("tSample", lTexture);
                    pixelAlpha.a = texMgr.texMaskNoise.copyToImage().getPixel(getX, getY).a;
                    float centerA = (float)(pixelAlpha.a/255);
                    tileBlend.setUniform("tileAlphaCenter", centerA);
                    ...
                    // (the fancier stuff mentioned in original post, linear interpolation between centerA and surrounding tile alpha values as found from noise texture, set those uniforms the same way)
                    terrainGrassLayer.draw( terrainLayer, &tileBlend );
                }
                else {
                    // tile blend shader not found, just draw tile with tile center alpha value
                    terrainLayer.setColor( pixelAlpha );
                    terrainGrassLayer.draw( terrainLayer );
                }
    ...
    if ( shaderLoaded )
        debugText += "\n... and shader loaded!";
    else
        debugText += "\n... and shader not loaded";

'Hope that helps without dumping all the prototype code I have. It doesn't appear the things related to GLSL are even being used, because they're apparently not being loaded.

Again, it's the shaderLoaded bool that's indicating the problem. The lack of console feedback is another (related?) mystery.

14
I'd be happy to entertain ideas, to double check how shaders ought to be configured and executed. Clearly, I've done something wrong, and I'm asking for suggestions as to what that might be.

I'll move on to other tasks, and come back to take another run at this in the near future. (shader practice was a primary goal for this current project)

All help is appreciated. :D

15
SFML game jam / Re: Revival attempt
« on: April 04, 2020, 03:30:28 am »
I second that motion. It's a good time to jam.

I recently met a 32 bytes/32 hours game challenge (use 32 bytes of working memory), 'just as a suggestion

Pages: [1] 2