gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Using wrapping textures with non-power of two sizes...pain!

#139607 - simonjhall - Sat Sep 08, 2007 2:26 am

Some context: it's Quake-on-the-DS again, and I'm trying to make the brush model textures which have non-standard sizes work correctly. The character models have non-po2 textures, but they're handled differently (and correctly).

In Quake, brush models (eg the world itself and ammo packs, not guns, rockets or players) have their meshes stored as a set of vertices, and the faces to be drawn are extracted from the bsp system at runtime to minimise overdraw etc etc. However to save on memory (I think...) texture co-ordinates are not stored - instead the level designer 'projects' their chosen texture map onto their chosen surface (each surface can have a different texture). This projection (a four-component vector) is then stored per face.

In order to render a textured surface, the Quake software renderer (and QuakeDS) compute these texture co-ordinates at run time (as in every single frame). GLQuake computes the co-ordinates at load time and store them alongside the vertex info.

The problem is that there are a few textures - for instance the Quake logo in the entrance hall and the skill level labels on the sides of the three teleporters - that have non-power-of-two sizes. For instance the Quake logo is 288x64. The designers exploit the fact that the software renderer allows texture wrapping, and often the co-ordinates that are generated don't lie in the range 0.0-1.0 - again the Quake logo has one of it's corners at (-1.778, 5).

So what can I do with this on the DS? I've tried lots of solutions which involve adjusting the UVs to fit into 0.0-1.0, but I can't think of anything which would allow you to draw a quad with co-ords (-0.5, -0.5) (0.5, -0.5) (0.5, 0.5) (-0.5, 0.5).
OpenGL won't allow a texture of 288x64, so GLQuake resamples the texture (ie it stretches it) up to 512x64 and when it generates its texture co-ordinates (at load time) it does some divides to make sure the co-ords are correct.

Does anyone have any suggestions of what I ought to do?
Bear in mind,
- there's not enough memory to pre-generate texture co-ordinates, so it needs to be done at runtime
- textures are loaded from disk on an as-needed basis (ie deferred loading), so any resizing would need to be done per-load or on first-load then stored to disk...

I'm not a graphics person, so I'm not too familiar with dealing with these sorts of problems :-D
_________________
Big thanks to everyone who donated for Quake2

#139614 - elhobbs - Sat Sep 08, 2007 4:17 am

if all of the non-power of two textures are non-tiling then you can load them by horizontal line into a power of two block so that they are aligned to top and left edge. For the texture coords you can subtract the texturemins from all of the coords after you calculate them. I may be mistaken but the ds does not seam to want the coords from 0 to 1 but rather from 0 to texture width

this is the code that I use in a surface cache based renderer for the ds where vec is the current vertext
Code:

      s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
      s = s - fa->texturemins[0];
      
      t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
      t  = t - fa->texturemins[1];

#139639 - simonjhall - Sat Sep 08, 2007 2:53 pm

Ok, I just tried it...it almost works, but it has the effect of aligning all textures to the left of the face they're on. So if you had a quad which had tex co-ords (0.5, 0) (1.0, 0) (1.0, 1.0) (0.5, 1.0) it'll draw (0, 0) (0.5, 0) (0.5, 1.0) (0, 1.0) instead since the mins will be (0.5, 0). This has the effect of making the logo in the entrance hall say QuakQ since it's made of two faces :-D

However it's a good idea though - I should be able to compute some kludge factor at the same time as texturemins[] is computed...hmm...thanks!
_________________
Big thanks to everyone who donated for Quake2

#139644 - elhobbs - Sat Sep 08, 2007 3:07 pm

you may want to just try it without subtracting texturemins to see what happens. the more I think about it I do not think you need to do any divides or compensation for the different texture widths because they are not tiling

#139661 - simonjhall - Sat Sep 08, 2007 7:02 pm

Ok I think I may have done it, but there are still some textures which exploit wrapping which I can't handle (eg the left and right teleporter in the entrance hall).
Basically to generate the co-ordinates correctly (ish) I use the texturemins variable like your said, but when I'm building that variable I shunt it and the maximum texture position up and down by the texture size until it's in the range 0 - 1 (or 0 - width in texels).

eg,
Code:
if (next_size_up(tex->texture->width) != tex->texture->width)
   {
      int x_shunt = 0;
      while (mins[0] + x_shunt < 0)
         x_shunt += tex->texture->width;
      
      while (mins[0] + x_shunt > tex->texture->width)
         x_shunt -= tex->texture->width;
      
      while (maxs[0] + x_shunt < 0)
         x_shunt += tex->texture->width;
      
      while (maxs[0] + x_shunt > tex->texture->width)
         x_shunt -= tex->texture->width;
      
      if ((maxs[0] + x_shunt >= 0) && (maxs[0] + x_shunt <= tex->texture->width)
         && (mins[0] + x_shunt >= 0) && (mins[0] + x_shunt <= tex->texture->width))
      {
         printf("texture \"%s\" fits ok with x shunt %d\n", tex->texture->name, x_shunt);
      }
      else
      {
         printf("texture \"%s\" does not fit ok in x\n", tex->texture->name, x_shunt);
//         while(1);
      }
      s->texturemins[0] = x_shunt;
   }

This makes the magic shunt factor which is added onto all texture co-ordinates to place them in the correct place (assuming there's no wrapping).

One less thing left to do :-)
_________________
Big thanks to everyone who donated for Quake2

#139664 - Dood77 - Sat Sep 08, 2007 7:42 pm

Glad to see you're still battling with the old QuakeDS problems... Figured out that one where it forces you to look ahead when you walk a few steps? (Look down, then walk forward without touching the touchscreen.)
Also, I tried out that "navy seals" mod that someone around here wanted to know if it would work... It ran, but very slowly, and with the error that a texture is too big. (The gun was untextured, amongst other things.)
_________________
If I use a term wrong or something then feel free to correct, I?m not much of a programmer.

Original DS Phat obtained on day of release + flashme v7
Supercard: miniSD, Kingston 1GB, Kingston 2GB
Ralink chipset PCI NIC

#139679 - simonjhall - Sat Sep 08, 2007 8:58 pm

Was that with the Supercard RAM build or the regular one? If it's the regular one then it could be super low on RAM and swapping in out every frame (like the old days :-)

I'll have a look into that view flipping thing, and yeah I can replicate it pretty easily although I always thought it was by design...

EDIT: Yeah, it is by design. When you adjust the viewing angle in Quake and then move it'll flip the view back up after a few feet. If you keep changing the viewing angle whilst walking the view will not flip - and this is what QDS does.
GLQuake (for Windows) however does something slightly different when you're using the "use mouse" and +mlook option as the mouse is permenantly telling the game that is moving (regardless of the motion), hence does not flip when you walk. QDS only actually sets the view when you touch the screen, so will not flip if you're touching the screen and walking but will do if you touch then screen, let go then walk a little bit.

EDIT 2: you still wanna web site it up when I finally finish this?
_________________
Big thanks to everyone who donated for Quake2

#139706 - elhobbs - Sun Sep 09, 2007 2:58 am

thinking about it a little and actually testing it in glquake I think what you need to do is normalize the texture coords. I think this actually produces the correct/usable results
Code:

      s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
      t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
      
      t /= fa->texinfo->texture->height;
      s /= fa->texinfo->texture->width;

      s -= ((int)fa->texturemins[0]/(int)fa->texinfo->texture->width);
      t -= ((int)fa->texturemins[1]/(int)fa->texinfo->texture->height);

I am not sure if using ints on the texturemins coords is 100% but it makes all the textures in the start level align correctly

#139771 - Dood77 - Mon Sep 10, 2007 1:50 am

simonjhall wrote:
Was that with the Supercard RAM build or the regular one? If it's the regular one then it could be super low on RAM and swapping in out every frame (like the old days :-)

It was the RAM build... the maps were kinda big in that game too, plus it really required more buttons than you could access while aiming.
simonjhall wrote:
EDIT: Yeah, it is by design. When you adjust the viewing angle in Quake and then move it'll flip the view back up after a few feet. If you keep changing the viewing angle whilst walking the view will not flip - and this is what QDS does.
GLQuake (for Windows) however does something slightly different when you're using the "use mouse" and +mlook option as the mouse is permenantly telling the game that is moving (regardless of the motion), hence does not flip when you walk. QDS only actually sets the view when you touch the screen, so will not flip if you're touching the screen and walking but will do if you touch then screen, let go then walk a little bit.

Ah, that makes much sense. Suppose you could hack this into an option on the menu? And while we're on the mouse-subject, the mouse speed variable still doesn't work...

simonjhall wrote:
EDIT 2: you still wanna web site it up when I finally finish this?

Yeah of course, I tried to do some tricky javascript+php to get the flash menu to look the same and not be flash anymore, and read from an external file to get the menu titles and link locations, but I failed, to say the least. Maybe I'll have another go.
_________________
If I use a term wrong or something then feel free to correct, I?m not much of a programmer.

Original DS Phat obtained on day of release + flashme v7
Supercard: miniSD, Kingston 1GB, Kingston 2GB
Ralink chipset PCI NIC

#139798 - simonjhall - Mon Sep 10, 2007 9:40 am

I'll have a go with that navy seal mod if I can find it. Performance has definately improved since I gave you that build, but playing from the Supercard is still slow. Also if the texture was too big to fit the gun then, it will be still!

And the mouse sensitivity settings thing is something I turn off in a profile build, so that's probably what I gave you! It's very easy to turn back on...but I must remember to do so!

BTW: yeah, playing from the Supercard is slow. It gets better from cards where you can crank up the speed (eg M3, Opera, EZ flash) but it's still slower than playing from main memory.
_________________
Big thanks to everyone who donated for Quake2