Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Exchange / Question about opengl texture coordinates
- - By bestguigui Date 2015-11-04 18:04
Hi there !

I have a question about how Gosu handles the textures. For what I understand, you optimize the Gosu::Images into a bigger texture than can take more images than the one I'm loading.

An opengl texture handles coordinates from 0.0 to 1.0, but because you manage images differently, you provide gl_tex_info and variables right, left, top and bottom to help us know the correct coordinates. This is the situation, and as you already know I'm not totally happy with it because :
- I would need texture repetition, using for example "2.0" to double it, which is impossible in current situation
- I would like to specify a cropped section of the texture, which is difficult.

I can deal with the first point, not the second one. Because I would like to use a Gosu::Image directly for 3D models made in a 3D software, in OBJ format to be precise, I really NEED to be able to use real coordinates... And then I started to think about it.

1.0 should be the width, also the height.

For width, I guess we could say that 1.0 could be represented by gl_tex_info.right - gl_tex_info.left, so it should be possible to ask for example for the coordinate 0.5, and it's easy then to say that it should be self.gl_tex_info.left + 0.5 * (self.gl_tex_info.right - self.gl_tex_info.left).

I didn't try display yet, but it should work. Replacing "0.5" with any value could work, as long as the value is between 0.0 and 1.0.

The problem I have is about the Y value. I don't get why the bottom value is bigger than the top value, because OpenGL is supposed to have the origin point on the bottom left corner (0, 0). Can you explain me that ?
Parent - - By jlnr (dev) Date 2015-11-07 15:43
Thanks for analysing the issues with gl_tex_info. I am a complete idiot when it comes to OpenGL, so I'm glad that the feature even works as well as it apparently does!
Fixing the first issue would be relatively easy by introducing a :single_texture => true flag in the Image constructor. (This would also fix the second issue.) I don't have the time to release a new Gosu version in the next days, though :(
As for the second issue, you are right that Gosu uses inverted Y coordinates - but at least it does so consistently (y=0 is always the top). Here are the calculations for gl_tex_info:

https://github.com/gosu/gosu/blob/master/src/Graphics/TexChunk.cpp#L11-L14

If you want to translate the coordinates to a bottom-to-top coordinate system, you can use 1 - tex_info.top and 1 - tex_info.bottom.

I guess you could even add a few helper methods on Image or GLTexInfo to wrap away all these calculations.
Parent - By bestguigui Date 2015-11-07 15:52 Edited 2015-11-07 17:40
Thanks jlnr ! I was sure that was the main "issue" there.

I will try to use the "1.0 - " trick. To be able to use a :single_texture flag would of course solve everything, but we would lose your optimizations, and I don't want that. Also, I plan to add some new methods, like you suggest, directly for any Gosu user, as long that he / she uses version >= 0.9 (I don't want to preserve compatibility with the old way of passing Gosu::Window to anything).

I'll try and let you know.

It will be maybe good to reference my new website as a french tutorial one of these days : http://www.retrorender.net
Even if it's still a really really early release :)

EDIT :

that way, it works :

class Gosu::GLTexInfo
  def tex_coord_2d(x, y)
    tex_x = self.left + x * (self.right - self.left)
    tex_y = (self.bottom + y * (self.top - self.bottom))
    glTexCoord2d(tex_x, tex_y)
  end
 
  def bottom_left;  tex_coord_2d(0.0, 0.0);  end
  def bottom_right;  tex_coord_2d(1.0, 0.0);  end
  def top_left;  tex_coord_2d(0.0, 1.0);  end
  def top_right;  tex_coord_2d(1.0, 1.0);  end
end

class Gosu::Image
  # x, y and z are relative to the center of the image
  def draw_3d(x, y, z, options = {})
    width, height = self.width, self.height
    x, y, w, h = 0.0, 0.0, 1.0, 1.0

    if options.has_key?(:rect)
      # rect uses the convention [x, y, w, h], expressed in opengl (from 0.0 to 1.0, origin on bottom-left corner)
      x, y, w, h = options[:rect][0].to_f, options[:rect][1].to_f, options[:rect][2].to_f, options[:rect][3].to_f
      x = 0.0 if x < 0.0 or x > 1.0
      y = 0.0 if y < 0.0 or y > 1.0
      w = 0.0 if w < 0.0 or w > 1.0
      h = 0.0 if h < 0.0 or h > 1.0
      width, height = w * self.width, h * self.height
    end
   
    glBindTexture(GL_TEXTURE_2D, self.gl_tex_info.tex_name)
    glEnable(GL_ALPHA_TEST)
    glPushMatrix
    glTranslate(x, y, z)
    glScale(width, height, 1.0)   
   
    if options.has_key?(:rot)
      # rot uses the convention [x, y, z], expressed in degrees
      glRotate(options[:rot][0], 1, 0, 0)
      glRotate(options[:rot][1], 0, 1, 0)
      glRotate(options[:rot][2], 0, 0, 1)
    end

    glBegin(GL_QUADS)
      self.gl_tex_info.tex_coord_2d(x, y); glVertex3f(-0.5, -0.5, 0.0)
      self.gl_tex_info.tex_coord_2d(x + w, y); glVertex3f(0.5, -0.5, 0.0)
      self.gl_tex_info.tex_coord_2d(x + w, y + h); glVertex3f(0.5, 0.5, 0.0)
      self.gl_tex_info.tex_coord_2d(x, y + h); glVertex3f(-0.5, 0.5, 0.0)
    glEnd
    glPopMatrix
    glDisable(GL_ALPHA_TEST)
  end
end

So I can pass any value from 0.0 to 1.0 to both x and y in the method tex_coord_2d(x, y), or even use the 4 helpers to directly set the coordinate of one corner :)
So I can draw a Sprite in a 3D environnement, with crop and rotation, directly in one method call :)
Up Topic Gosu / Gosu Exchange / Question about opengl texture coordinates

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill