New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mipmaps to sf::Texture #498

Closed
wants to merge 1 commit into
base: master
from

Conversation

Projects
None yet
8 participants
@wintertime
Contributor

wintertime commented Nov 29, 2013

I think not having mipmaps in SFML is something that needs to be changed, because it helps when using setScale and when putting a larger texture onto a smaller sized shape.
As I liked to have it myself I added this to sf::Texture and it should also fix Issue #123 .
I made it such that its backwards compatible and keeps deactivated until used. When not used it just adds a check of a status variable on some method calls. Its possible to use all underlying modes in combination with the smooth setting.
This uses the texture parameter to generate the mipmaps.
It looks like its working for me, but you would probably want to test it before applying.

PS:
I also put some effort into adding code for using the newer glGenerateMipmapExt and glGenerateMipmap and making mipmaps available for the internal texture of sf::RenderTexture. You can view those other commits in my forked repository at https://github.com/wintertime/SFML/tree/mipmaps .
I did not include those here, because I get graphical glitches sometimes although other times it looks like it works. I think there is either something wrong with the order of calls to the OpenGL functions or I experienced the driver bug mentioned on http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation .

Here is a small test program for trying it out, you can change a few parameters in the code and then look at a larger area of the texture squeezed into the window by pressing Numpad6 so you can watch the effect of mipmaps:

#include "SFML/Graphics.hpp"
#include <vector>

int32_t windowx(512);
int32_t windowy(512);
bool fullscreen(false);

void CreateTexture(sf::Texture& tex,int sz,int w,int b) {
  std::vector<sf::Uint8> pix;
  pix.resize(sz*sz*4);
  for(int y(0);y<sz;y+=w+b) {
    int ty(0);
    for(;ty<w && y+ty<sz;++ty)
      for(int x(0);x<sz;x+=w+b) {
        int tx(0);
        for(;tx<w && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=255;
          pix[index+1]=0;
          pix[index+2]=0;
          pix[index+3]=255;
        }
        for(;tx<w+b && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=0;
          pix[index+1]=255;
          pix[index+2]=0;
          pix[index+3]=255;
        }
      }
    for(;ty<w+b && y+ty<sz;++ty)
      for(int x(0);x<sz;x+=w+b) {
        int tx(0);
        for(;tx<w && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=0;
          pix[index+1]=0;
          pix[index+2]=0;
          pix[index+3]=255;
        }
        for(;tx<w+b && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=0;
          pix[index+1]=0;
          pix[index+2]=255;
          pix[index+3]=255;
        }
      }
  }
  sf::Image img;
  img.create(sz,sz,&pix[0]);
  tex.loadFromImage(img);
}

int main(int argc,char* argv[]) {
  sf::RenderWindow window(sf::VideoMode(windowx,windowy),"Test",
                    fullscreen ? sf::Style::Fullscreen : sf::Style::Default,
                    sf::ContextSettings(0,0,0,2,1));
  window.setVerticalSyncEnabled(1);

  sf::Texture tex;
  float scale(1.0f);
  int sz(512);
  int w(128);
  int b(128);

  //tex.setSmooth(true);
  tex.setUsedMipmaps(2);
  tex.setRepeated(true);
  CreateTexture(tex,sz,w,b);

  sf::Event event;
  while(window.isOpen()) {
    window.clear();
    sf::RectangleShape shape(sf::Vector2f(512,512));
    shape.setTexture(&tex);
    shape.setTextureRect(sf::IntRect(0,0,sz*scale,sz*scale));
    window.draw(shape);
    window.display();

    while(window.pollEvent(event)) {
      if(event.type==sf::Event::Closed)
        window.close();
      else if(event.type==sf::Event::KeyPressed) {
        switch(event.key.code) {
        default:
          continue;
        case sf::Keyboard::Numpad6:
          scale*=1.1f;
          continue;
        case sf::Keyboard::Numpad5:
          scale=1.0f;
          continue;
        case sf::Keyboard::Numpad4:
          scale/=1.1f;
          continue;
        case sf::Keyboard::Numpad9:
          sz*=2;
          break;
        case sf::Keyboard::Numpad3:
          sz/=2;
          if(sz<1)
            sz=1;
          break;
        case sf::Keyboard::Numpad7:
          if(w<sz/2)
            w*=2;
          break;
        case sf::Keyboard::Numpad1:
          w/=2;
          if(w<1)
            w=1;
          break;
        case sf::Keyboard::Numpad8:
          if(b<sz/2)
            b*=2;
          break;
        case sf::Keyboard::Numpad2:
          b/=2;
          if(b<1)
            b=1;
          break;
        }
        CreateTexture(tex,sz,w,b);
      }
    }
  }

  return 0;
}

@ghost ghost assigned LaurentGomila Nov 29, 2013

@LaurentGomila

This comment has been minimized.

Show comment
Hide comment
@LaurentGomila

LaurentGomila Nov 29, 2013

Member

Thanks a lot for your contribution.

The test program is great, but we can't test it unless we apply your patch. Could you provide something that we could test out of the box? Like a compiled executable, screenshots, a video, or a self-contained example that uses OpenGL rather than your SFML modifications.

Member

LaurentGomila commented Nov 29, 2013

Thanks a lot for your contribution.

The test program is great, but we can't test it unless we apply your patch. Could you provide something that we could test out of the box? Like a compiled executable, screenshots, a video, or a self-contained example that uses OpenGL rather than your SFML modifications.

@wintertime

This comment has been minimized.

Show comment
Hide comment
@wintertime

wintertime Nov 29, 2013

Contributor

Ah well, I could modify the test program to add key bindings for the smooth and mipmap setting, compile it and zip it; and also give you a zip with the changed SFML version of this pull request precompiled for MinGW4.7.1. Or I could make a screenshot where the colors from the test program fade together into grey when squeezing each 4 square areas of the large repeated texture into a point, but that seems much less useful than trying it interactively.
But I would think you could test it more thoroughly if you fetch from my fork or clone it, compile yourself and you are able to tweak the test program? You could then also easily checkout the other commits I didn't include in the pull request if you like to do some more experimentation on them.

Contributor

wintertime commented Nov 29, 2013

Ah well, I could modify the test program to add key bindings for the smooth and mipmap setting, compile it and zip it; and also give you a zip with the changed SFML version of this pull request precompiled for MinGW4.7.1. Or I could make a screenshot where the colors from the test program fade together into grey when squeezing each 4 square areas of the large repeated texture into a point, but that seems much less useful than trying it interactively.
But I would think you could test it more thoroughly if you fetch from my fork or clone it, compile yourself and you are able to tweak the test program? You could then also easily checkout the other commits I didn't include in the pull request if you like to do some more experimentation on them.

@LaurentGomila

This comment has been minimized.

Show comment
Hide comment
@LaurentGomila

LaurentGomila Nov 29, 2013

Member

But I would think you could test it more thoroughly if you fetch from my fork or clone it, compile yourself and you are able to tweak the test program? You could then also easily checkout the other commits I didn't include in the pull request if you like to do some more experimentation on them.

That would be best, yes. But unfortunately I have very little time for such things... :( So it is more likely to progress if I can test it with as few work as possible.

Member

LaurentGomila commented Nov 29, 2013

But I would think you could test it more thoroughly if you fetch from my fork or clone it, compile yourself and you are able to tweak the test program? You could then also easily checkout the other commits I didn't include in the pull request if you like to do some more experimentation on them.

That would be best, yes. But unfortunately I have very little time for such things... :( So it is more likely to progress if I can test it with as few work as possible.

@wintertime

This comment has been minimized.

Show comment
Hide comment
@wintertime

wintertime Nov 29, 2013

Contributor

Compiled SFML: https://www.dropbox.com/s/aa05qxpjuqg3t0e/SFML-mipmaps1.zip
Compiled Test (debug and release version): https://www.dropbox.com/s/cr7hant3n8m5qv3/test-mipmaps1.zip
A screenshot: https://www.dropbox.com/s/qqihanpaowv00l2/mipmaps1.png

Just unpack the SFML package, then unpack the test into the bin directory or copy over the dll files to where you put the exe files.

Best way to try it out:

  • Tap Numpad 6 about 8 times to zoom out fast until it looks grey.
  • Tap Numpad 4 once to zoom in a bit again.
  • Hold Numpad + for a slower zoom out until it looks like on the screenshot.
  • Use function keys to switch mipmap (F1, F2, F3) and smooth (F5, F6) settings.

Updated code for the test program so you can see all available keys (there are more):

#include "SFML/Graphics.hpp"
#include <vector>

int32_t windowx(512);
int32_t windowy(512);
bool fullscreen(false);

void CreateTexture(sf::Texture& tex,int sz,int w,int b) {
  std::vector<sf::Uint8> pix;
  pix.resize(sz*sz*4);
  for(int y(0);y<sz;y+=w+b) {
    int ty(0);
    for(;ty<w && y+ty<sz;++ty)
      for(int x(0);x<sz;x+=w+b) {
        int tx(0);
        for(;tx<w && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=255;
          pix[index+1]=0;
          pix[index+2]=0;
          pix[index+3]=255;
        }
        for(;tx<w+b && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=0;
          pix[index+1]=255;
          pix[index+2]=0;
          pix[index+3]=255;
        }
      }
    for(;ty<w+b && y+ty<sz;++ty)
      for(int x(0);x<sz;x+=w+b) {
        int tx(0);
        for(;tx<w && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=0;
          pix[index+1]=0;
          pix[index+2]=0;
          pix[index+3]=255;
        }
        for(;tx<w+b && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=0;
          pix[index+1]=0;
          pix[index+2]=255;
          pix[index+3]=255;
        }
      }
  }
  sf::Image img;
  img.create(sz,sz,&pix[0]);
  tex.loadFromImage(img);
}

int main(int argc,char* argv[]) {
  sf::RenderWindow window(sf::VideoMode(windowx,windowy),"Test",
                    fullscreen ? sf::Style::Fullscreen : sf::Style::Default,
                    sf::ContextSettings(0,0,0,2,1));
  window.setVerticalSyncEnabled(1);

  sf::Texture tex;
  float scale(1.0f);
  int sz(512);
  int w(128);
  int b(128);
  bool smooth(true);
  unsigned mipmaps(2);
  bool repeat(true);

  tex.setSmooth(smooth);
  tex.setUsedMipmaps(mipmaps);
  tex.setRepeated(repeat);
  CreateTexture(tex,sz,w,b);

  sf::Event event;
  while(window.isOpen()) {
    window.clear();
    sf::RectangleShape shape(sf::Vector2f(512,512));
    shape.setTexture(&tex);
    shape.setTextureRect(sf::IntRect(0,0,sz*scale,sz*scale));
    window.draw(shape);
    window.display();

    while(window.pollEvent(event)) {
      if(event.type==sf::Event::Closed)
        window.close();
      else if(event.type==sf::Event::KeyPressed) {
        switch(event.key.code) {
        default:
          continue;
        case sf::Keyboard::Add:
          scale+=1.0f;
          continue;
        case sf::Keyboard::Subtract:
          scale-=1.0f;
          if(scale*1024.0f<=1.0f)
            scale=1.0f/1024.0f;
          continue;
        case sf::Keyboard::Numpad6:
          scale*=2.0f;
          continue;
        case sf::Keyboard::Numpad5:
          scale=1.0f;
          continue;
        case sf::Keyboard::Numpad4:
          scale/=2.0f;
          continue;
        case sf::Keyboard::Numpad9:
          sz*=2;
          break;
        case sf::Keyboard::Numpad3:
          sz/=2;
          if(sz<1)
            sz=1;
          break;
        case sf::Keyboard::Numpad7:
          if(w<sz/2)
            w*=2;
          break;
        case sf::Keyboard::Numpad1:
          w/=2;
          if(w<1)
            w=1;
          break;
        case sf::Keyboard::Numpad8:
          if(b<sz/2)
            b*=2;
          break;
        case sf::Keyboard::Numpad2:
          b/=2;
          if(b<1)
            b=1;
          break;
        case sf::Keyboard::F7:
          repeat=false;
          break;
        case sf::Keyboard::F8:
          repeat=true;
          break;
        case sf::Keyboard::F5:
          smooth=false;
          break;
        case sf::Keyboard::F6:
          smooth=true;
          break;
        case sf::Keyboard::F1:
          mipmaps=0;
          break;
        case sf::Keyboard::F2:
          mipmaps=1;
          break;
        case sf::Keyboard::F3:
          mipmaps=2;
          break;
        }
        tex.setSmooth(smooth);
        tex.setUsedMipmaps(mipmaps);
        tex.setRepeated(repeat);
        CreateTexture(tex,sz,w,b);
      }
    }
  }

  return 0;
}
Contributor

wintertime commented Nov 29, 2013

Compiled SFML: https://www.dropbox.com/s/aa05qxpjuqg3t0e/SFML-mipmaps1.zip
Compiled Test (debug and release version): https://www.dropbox.com/s/cr7hant3n8m5qv3/test-mipmaps1.zip
A screenshot: https://www.dropbox.com/s/qqihanpaowv00l2/mipmaps1.png

Just unpack the SFML package, then unpack the test into the bin directory or copy over the dll files to where you put the exe files.

Best way to try it out:

  • Tap Numpad 6 about 8 times to zoom out fast until it looks grey.
  • Tap Numpad 4 once to zoom in a bit again.
  • Hold Numpad + for a slower zoom out until it looks like on the screenshot.
  • Use function keys to switch mipmap (F1, F2, F3) and smooth (F5, F6) settings.

Updated code for the test program so you can see all available keys (there are more):

#include "SFML/Graphics.hpp"
#include <vector>

int32_t windowx(512);
int32_t windowy(512);
bool fullscreen(false);

void CreateTexture(sf::Texture& tex,int sz,int w,int b) {
  std::vector<sf::Uint8> pix;
  pix.resize(sz*sz*4);
  for(int y(0);y<sz;y+=w+b) {
    int ty(0);
    for(;ty<w && y+ty<sz;++ty)
      for(int x(0);x<sz;x+=w+b) {
        int tx(0);
        for(;tx<w && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=255;
          pix[index+1]=0;
          pix[index+2]=0;
          pix[index+3]=255;
        }
        for(;tx<w+b && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=0;
          pix[index+1]=255;
          pix[index+2]=0;
          pix[index+3]=255;
        }
      }
    for(;ty<w+b && y+ty<sz;++ty)
      for(int x(0);x<sz;x+=w+b) {
        int tx(0);
        for(;tx<w && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=0;
          pix[index+1]=0;
          pix[index+2]=0;
          pix[index+3]=255;
        }
        for(;tx<w+b && x+tx<sz;++tx) {
          int index=((y+ty)*sz+(x+tx))*4;
          pix[index  ]=0;
          pix[index+1]=0;
          pix[index+2]=255;
          pix[index+3]=255;
        }
      }
  }
  sf::Image img;
  img.create(sz,sz,&pix[0]);
  tex.loadFromImage(img);
}

int main(int argc,char* argv[]) {
  sf::RenderWindow window(sf::VideoMode(windowx,windowy),"Test",
                    fullscreen ? sf::Style::Fullscreen : sf::Style::Default,
                    sf::ContextSettings(0,0,0,2,1));
  window.setVerticalSyncEnabled(1);

  sf::Texture tex;
  float scale(1.0f);
  int sz(512);
  int w(128);
  int b(128);
  bool smooth(true);
  unsigned mipmaps(2);
  bool repeat(true);

  tex.setSmooth(smooth);
  tex.setUsedMipmaps(mipmaps);
  tex.setRepeated(repeat);
  CreateTexture(tex,sz,w,b);

  sf::Event event;
  while(window.isOpen()) {
    window.clear();
    sf::RectangleShape shape(sf::Vector2f(512,512));
    shape.setTexture(&tex);
    shape.setTextureRect(sf::IntRect(0,0,sz*scale,sz*scale));
    window.draw(shape);
    window.display();

    while(window.pollEvent(event)) {
      if(event.type==sf::Event::Closed)
        window.close();
      else if(event.type==sf::Event::KeyPressed) {
        switch(event.key.code) {
        default:
          continue;
        case sf::Keyboard::Add:
          scale+=1.0f;
          continue;
        case sf::Keyboard::Subtract:
          scale-=1.0f;
          if(scale*1024.0f<=1.0f)
            scale=1.0f/1024.0f;
          continue;
        case sf::Keyboard::Numpad6:
          scale*=2.0f;
          continue;
        case sf::Keyboard::Numpad5:
          scale=1.0f;
          continue;
        case sf::Keyboard::Numpad4:
          scale/=2.0f;
          continue;
        case sf::Keyboard::Numpad9:
          sz*=2;
          break;
        case sf::Keyboard::Numpad3:
          sz/=2;
          if(sz<1)
            sz=1;
          break;
        case sf::Keyboard::Numpad7:
          if(w<sz/2)
            w*=2;
          break;
        case sf::Keyboard::Numpad1:
          w/=2;
          if(w<1)
            w=1;
          break;
        case sf::Keyboard::Numpad8:
          if(b<sz/2)
            b*=2;
          break;
        case sf::Keyboard::Numpad2:
          b/=2;
          if(b<1)
            b=1;
          break;
        case sf::Keyboard::F7:
          repeat=false;
          break;
        case sf::Keyboard::F8:
          repeat=true;
          break;
        case sf::Keyboard::F5:
          smooth=false;
          break;
        case sf::Keyboard::F6:
          smooth=true;
          break;
        case sf::Keyboard::F1:
          mipmaps=0;
          break;
        case sf::Keyboard::F2:
          mipmaps=1;
          break;
        case sf::Keyboard::F3:
          mipmaps=2;
          break;
        }
        tex.setSmooth(smooth);
        tex.setUsedMipmaps(mipmaps);
        tex.setRepeated(repeat);
        CreateTexture(tex,sz,w,b);
      }
    }
  }

  return 0;
}
@LaurentGomila

This comment has been minimized.

Show comment
Hide comment
@LaurentGomila

LaurentGomila Nov 29, 2013

Member

Thank you very much!

But I can't run the test, your compiler's DLLs are missing (libgcc_s_dw2, libgcc_s_sjlj, libstdc++, ...).

Member

LaurentGomila commented Nov 29, 2013

Thank you very much!

But I can't run the test, your compiler's DLLs are missing (libgcc_s_dw2, libgcc_s_sjlj, libstdc++, ...).

@wintertime

This comment has been minimized.

Show comment
Hide comment
@wintertime

wintertime Nov 29, 2013

Contributor

Oops, sorry. I checked with depends now what is needed and packaged the two dll files.
https://www.dropbox.com/s/303jfghwa56fn89/dll-files-mipmaps1.zip

Contributor

wintertime commented Nov 29, 2013

Oops, sorry. I checked with depends now what is needed and packaged the two dll files.
https://www.dropbox.com/s/303jfghwa56fn89/dll-files-mipmaps1.zip

@Caffeine-Addict

This comment has been minimized.

Show comment
Hide comment
@Caffeine-Addict

Caffeine-Addict Apr 22, 2014

Any news on this?

Caffeine-Addict commented Apr 22, 2014

Any news on this?

@Bromeon

This comment has been minimized.

Show comment
Hide comment
@Bromeon

Bromeon Apr 22, 2014

Member

The SFML development team has just been restructured. We need some time to organize ourselves and set new milestones, but once this is done, development will progress much faster :)

So we'll come back on this.

Member

Bromeon commented Apr 22, 2014

The SFML development team has just been restructured. We need some time to organize ourselves and set new milestones, but once this is done, development will progress much faster :)

So we'll come back on this.

@LaurentGomila LaurentGomila added undecided and removed feature labels May 20, 2014

@LaurentGomila LaurentGomila removed their assignment May 20, 2014

@LaurentGomila LaurentGomila removed this from the 2.x milestone May 20, 2014

@TankOs

This comment has been minimized.

Show comment
Hide comment
@TankOs

TankOs Jun 9, 2014

Member

I'd say let's postpone this to 2.x

Member

TankOs commented Jun 9, 2014

I'd say let's postpone this to 2.x

@Bromeon

This comment has been minimized.

Show comment
Hide comment
@Bromeon

Bromeon Jun 10, 2014

Member

I agree.

Member

Bromeon commented Jun 10, 2014

I agree.

@Bromeon Bromeon added this to the 2.x milestone Jun 10, 2014

@LaurentGomila

This comment has been minimized.

Show comment
Hide comment
@LaurentGomila

LaurentGomila Jun 10, 2014

Member

Why does it have a milestone if it's still 'undecided'?

Member

LaurentGomila commented Jun 10, 2014

Why does it have a milestone if it's still 'undecided'?

@Bromeon Bromeon removed this from the 2.x milestone Jun 10, 2014

@Bromeon

This comment has been minimized.

Show comment
Hide comment
@Bromeon

Bromeon Jun 10, 2014

Member

Probably a misunderstanding (milestone denoting the time the issue is evaluated rather than implemented). I removed it, let's agree on assigning milestones only for accepted issues, accompanied by the "s:accepted" label.

Member

Bromeon commented Jun 10, 2014

Probably a misunderstanding (milestone denoting the time the issue is evaluated rather than implemented). I removed it, let's agree on assigning milestones only for accepted issues, accompanied by the "s:accepted" label.

@TankOs

This comment has been minimized.

Show comment
Hide comment
@TankOs

TankOs Jun 10, 2014

Member

I liked it as it shows that we don't have to touch this until after 2.2.

Member

TankOs commented Jun 10, 2014

I liked it as it shows that we don't have to touch this until after 2.2.

@binary1248

This comment has been minimized.

Show comment
Hide comment
@binary1248

binary1248 Sep 25, 2014

Member

I'll probably look into this after gl_dev is complete and merged into master.

Member

binary1248 commented Sep 25, 2014

I'll probably look into this after gl_dev is complete and merged into master.

@eXpl0it3r eXpl0it3r removed the s:unassigned label Jan 8, 2015

@binary1248 binary1248 self-assigned this Mar 28, 2015

@binary1248 binary1248 added this to the 2.4 milestone Mar 29, 2015

@binary1248 binary1248 referenced this pull request May 11, 2015

Closed

Add support for mipmaps #123

@mantognini

This comment has been minimized.

Show comment
Hide comment
@mantognini

mantognini Jul 4, 2015

Member

Note: this is (really) old and cannot be used as is.

Member

mantognini commented Jul 4, 2015

Note: this is (really) old and cannot be used as is.

@binary1248

This comment has been minimized.

Show comment
Hide comment
@binary1248

binary1248 Sep 23, 2015

Member

Superseded by #973.

Member

binary1248 commented Sep 23, 2015

Superseded by #973.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment