# JOGL_Texturing_Specials



## Developer_X (13. Nov 2009)

Hi,
um nicht es nicht so schwer zu haben mit JOGL habe ich mir selbst ein paar "Basis klassen" geschrieben,
mit denen ich ganz einfach einen text, eine box, einen cube, usw.. ganz einfach, mit net methode zaubern kann.
Nun aber zu meinem Problem:
Die Textur zu laden, das ganze try und catch, das wollte ich auf eine außenstehende Klasse verlangern.
Ich erstellte mir also die Klasse Textur:

```
package Geometric;

import com.sun.opengl.util.texture.*;

public class Textur
{
	boolean loaded = false;
	Texture texture; 
	
	public void load(String texture_file)
	{
		try
		{
			texture = TextureIO.newTexture(getClass().getClassLoader().getResourceAsStream(texture_file), false, TextureIO.JPG);
			loaded = true;
		}
		catch(Exception e)
		{
			System.out.println(texture_file+" does not exist or may cannot be found.");
		}
	}
	public void bind()
	{
		if(loaded)
			texture.bind();
		else
			System.out.println("Texture has to be loaded (correctly).");
	}
}
```

Dann habe ich noch eine Klasse namens GeoOD (Geometric.Objects.Drawer) geschrieben,
in ihr gibt es unter anderem auch die methode, drawBox();
(Ausschnitt)

```
public void drawBox(GL2 gl, Color color, float width, float height, float wide)
	{
		boolean lightingState;
		gl.glPushMatrix();
		lightingState = gl.glIsEnabled(GL2.GL_LIGHTING);
		gl.glDisable(GL2.GL_LIGHTING);
	 	gl.glColor3d(color.getRed() / 255.0, color.getGreen() / 255.0, color.getBlue() / 255.0);
	 	
	 	gl.glTranslatef(0,0,+wide/2);
	 	gl.glRectf(-width/2,-height/2,width/2,height/2);
	 	gl.glTranslatef(0,0,-wide/2);
	 	gl.glTranslatef(0,0,-wide/2);
	 	gl.glRectf(-width/2,-height/2,width/2,height/2);
	 	gl.glTranslatef(0,0,+wide/2);

	 	gl.glTranslatef(0,height/2,0);
	 	gl.glRotatef(90,1,0,0);
	 	gl.glRectf(-width/2,-wide/2,width/2,wide/2);
	 	gl.glRotatef(-90,1,0,0);
	 	gl.glTranslatef(0,-height/2,0);
	 	gl.glTranslatef(0,-height/2,0);
	 	gl.glRotatef(90,1,0,0);
	 	gl.glRectf(-width/2,-wide/2,width/2,wide/2);
	 	gl.glRotatef(-90,1,0,0);
	 	gl.glTranslatef(0,height/2,0);
	 	
	 	gl.glTranslatef(width/2,0,0);
	 	gl.glRotatef(90,0,1,0);
	 	gl.glRectf(-wide/2,-height/2,wide/2,height/2);
	 	gl.glRotatef(-90,0,1,0);
	 	gl.glTranslatef(-width/2,0,0);
	 	gl.glTranslatef(-width/2,0,0);
	 	gl.glRotatef(90,0,1,0);
	 	gl.glRectf(-wide/2,-height/2,wide/2,height/2);
	 	gl.glRotatef(-90,0,1,0);
	 	gl.glTranslatef(width/2,0,0);
	 	
	 	if(lightingState)
		{
			gl.glEnable(GL2.GL_LIGHTING);
		}	
	}
```

Nach diesem ganzen hier, hatte ich mir gedacht, die klasse die von GLEventListener added, da mache ich das hier:

```
Textur t = new Textur();
	@Override
	public void init(final GLAutoDrawable drawable) 
	{       
		GL2 gl = drawable.getGL().getGL2();
		gl.glEnable(GL.GL_TEXTURE_2D);
		gl.glEnable(GL.GL_DEPTH_TEST);
		
		gl.glActiveTexture(GL.GL_TEXTURE0);

		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);

		gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);		
		
		gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	    t.load("Pic.jpg");
	}
    GeoOD g = new GeoOD();

	@Override
	public void display(final GLAutoDrawable drawable) 
	{
		gl = drawable.getGL().getGL2();

		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		gl.glLoadIdentity();

		glu.gluLookAt(0, 0, 6, 0, 0, 0, 0, 1, 0);

		// Prepare light parameters.
        float SHINE_ALL_DIRECTIONS = 1;
        float[] lightPos = {-30, 0, 0, SHINE_ALL_DIRECTIONS};
        float[] lightColorAmbient = {0.2f, 0.2f, 0.2f, 1f};
        float[] lightColorSpecular = {0.8f, 0.8f, 0.8f, 1f};

        // Set light parameters.
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, lightPos, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_AMBIENT, lightColorAmbient, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPECULAR, lightColorSpecular, 0);

        // Enable lighting in GL.
        gl.glEnable(GL2.GL_LIGHT1);
        gl.glEnable(GL2.GL_LIGHTING);

        gl.glTranslatef(X,Y,Z);

        t.bind();
        g.drawBox(gl, Color.green,1,2,3);
	}
```
Doch ich habe keine Ahnung warum keine Textur angezeigt wird, wenn ich das ganze starte.
Er meldet mir auch nicht die Fehler-Ausgaben, die ich in der Klasse Textur geschrieben habe.

Ich denke das ganze funktioniert, nur das mit der Textur coordinate funktioniert vielleicht nicht.
Liegt es daran, ?
Danke für eure Hilfen (besonders Fancy ^^),
Developer_X.


----------



## Developer_X (13. Nov 2009)

und warum ist es eig. so dunkel?
Sobald man die methode load aufruft, bei texture, ist es so dunkel,
vorher, wenn man nur die instanz davon erstellt, ist es noch so hell wie vorher.
Es spielt doch nur ne rolle ob man das "bind"ed oder nicht?


----------



## Evil-Devil (13. Nov 2009)

Es ist so dunkel, weil dein Licht nur auf die jeweilige ausgerichtete Stelle leuchtet. Wenn du GL_LIGHTS deaktivierst, dann ist es wieder hell, aber dann wirst du auch keine Schatten erzeugen können


----------



## Spacerat (13. Nov 2009)

@DX: Du weisst schon, das du dir solche Klassen, wie deine oben, ziemlich schnell sparen kannst, wenn du nur anfangen würdest, Tutorials zu lesen. In denen erfährt man nämlich schon so ziemlich am Anfang etwas über Listen und was man damit macht.


----------



## Guest2 (14. Nov 2009)

Moin,

(in Kürze, muss gleich wieder weg, wenn Du später was neues hast, kannst Du ja noch mal posten, dann Antworte ich detaillierter))



Developer_X hat gesagt.:


> Ich denke das ganze funktioniert, nur das mit der Textur coordinate funktioniert vielleicht nicht.
> Liegt es daran, ?



Genau, glRectf erzeugt ihmo  keine Texturkoordinaten, kann also so nicht einfach mit einer Textur belegt werden.



Developer_X hat gesagt.:


> und warum ist es eig. so dunkel?
> Sobald man die methode load aufruft, bei texture, ist es so dunkel,
> vorher, wenn man nur die instanz davon erstellt, ist es noch so hell wie vorher.
> Es spielt doch nur ne rolle ob man das "bind"ed oder nicht?



Ja, eigentlich hast Du genau recht! 
Nur steckt in dem TextureIO.newTexture auch schon ein bind und das gilt solange bis eine neue Textur gebunden wird oder explizit keine (0) gebunden wird (gl.glBindTexture(GL.GL_TEXTURE_2D, 0)

Vermutung: Da keine Texturkoordinaten gesetzt werden, gelten 0.0/0.0 als Texturkoordinaten damit müsste der Würfel die Farbe haben die dem linken oberen Pixel deiner Textur entspricht.

Versuche mal folgenden Code zu verstehen (der macht genau dasselbe wie deine drawBox()):


```
import java.nio.FloatBuffer;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;

import com.sun.opengl.util.BufferUtil;

public class Cube {
	
	private static final float[] cube = new float[] { 
        1.0f, 1.0f,-1.0f, 0.0f, 0.0f,   -1.0f, 1.0f,-1.0f, 0.0f, 1.0f,   -1.0f, 1.0f, 1.0f, 1.0f, 1.0f,    1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        1.0f,-1.0f, 1.0f, 0.0f, 0.0f,   -1.0f,-1.0f, 1.0f, 0.0f, 1.0f,   -1.0f,-1.0f,-1.0f, 1.0f, 1.0f,    1.0f,-1.0f,-1.0f, 1.0f, 0.0f,
        1.0f, 1.0f, 1.0f, 0.0f, 0.0f,   -1.0f, 1.0f, 1.0f, 0.0f, 1.0f,   -1.0f,-1.0f, 1.0f, 1.0f, 1.0f,    1.0f,-1.0f, 1.0f, 1.0f, 0.0f,
        1.0f,-1.0f,-1.0f, 0.0f, 0.0f,   -1.0f,-1.0f,-1.0f, 0.0f, 1.0f,   -1.0f, 1.0f,-1.0f, 1.0f, 1.0f,    1.0f, 1.0f,-1.0f, 1.0f, 0.0f,
       -1.0f, 1.0f, 1.0f, 0.0f, 0.0f,   -1.0f, 1.0f,-1.0f, 0.0f, 1.0f,   -1.0f,-1.0f,-1.0f, 1.0f, 1.0f,   -1.0f,-1.0f, 1.0f, 1.0f, 0.0f,
        1.0f, 1.0f,-1.0f, 0.0f, 0.0f,    1.0f, 1.0f, 1.0f, 0.0f, 1.0f,    1.0f,-1.0f, 1.0f, 1.0f, 1.0f,    1.0f,-1.0f,-1.0f, 1.0f, 0.0f};
	
	private GL2						gl			= null;

	private FloatBuffer				vaTriangle	= null;

	
	public Cube() {

		vaTriangle = BufferUtil.newFloatBuffer(cube.length);
		vaTriangle.put(cube, 0, cube.length);
		vaTriangle.rewind();

	}
	

	public void init(final GLAutoDrawable drawable) {

		gl = drawable.getGL().getGL2();

		gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);

	}

	
	public void draw(final float height, final float width, final float depth) {

		gl.glScalef(height, width, depth);
		
		gl.glVertexPointer(3, GL.GL_FLOAT, 5 * (Float.SIZE / 8), vaTriangle.position(0));
		gl.glTexCoordPointer(2, GL.GL_FLOAT, 5 * (Float.SIZE / 8), vaTriangle.position(3));
		gl.glDrawArrays(GL2.GL_QUADS, 0, vaTriangle.capacity() / 5);

	}

}
```

Die komische Zahlenkolonne am Anfang sind 6 Vierecke (a 4 Ecken  ) mit jeweils 5 Werten (x, y, z, s (Textur x), t (Textur y)).

Damit sollte das mit Deiner Textur gehen.

(Mit dem Licht stimmt ihmo auch noch was nicht, aber experimentier erstmal wieder en bissel  )


Gruß,
Fancy


----------



## Guest2 (15. Nov 2009)

So, bin wieder da.

Erstmal sorry, der Cube Code oben hat zwei "Unschönheiten":

- vaTriangle ist ein denkbar dummer Bezeichner für ein Buffer der Vierecke enthält.  
- der Cube ist mit einem Skalierungsfaktor von einer Einheit zwei Einheiten groß.

(Drei mal darf jetzt geraten werden was die Klasse vor dem ummodeln wohl dargestellt hat  )


Damit das mit der Beleuchtung und der Textur richtig hinhaut, brauchst Du für jeden Eckpunkt der 6 Vierecke folgende Werte:

x, y, z = das sind die Koordinaten des Eckpunktes
s, t      = das sind die Texturkoordinaten
nx, ny, nz = das ist die Normale (eine Art Pfeil der senkrecht auf der Fläche steht)

Das von Dir verwendete glRect erzeugt aber nur die x, y, z Werte und nicht die anderen. Damit kannst Du das weder beleuchten noch eine Textur auflegen. 

Auch sind die Beleuchtungsanweisungen in Deiner drawBox() unglücklich. Du rufst glDisable(GL2.GL_LIGHTING) auf, zeichnest und rufst dann glEnable(GL2.GL_LIGHTING) auf. Damit wird Deine Box nie beleuchtet! In OpenGL braucht man keine Beleuchtung um etwas darzustellen, wenn keine Beleuchtung aktiv ist, werden einfach nur die Farben der Eckpunkte bzw. die Textur zur Darstellung genutzt. Willst Du die Berechnung der Beleuchtung nutzen, dann musst Du vor dem zeichnen glEnable(GL2.GL_LIGHTING)  aufrufen.

Deine Idee mit dem auslagern der Texturfunktionen in eine Texturklasse und den Geometriekörpern in eine andere Klasse finde ich aber gut! Ich mache das so ähnlich. Wenn Du nämlich später komplexere Klassen hast, die auf OpenGL Funktionen arbeiten,
 ergibt das ein einheitlicheres Bild, z.B. in etwa so:


```
public class Show {
	
	private final Shader shader;
	private final Projection projection;
	private final Modelview modelview;
	private final Texture texture;
	private final Vertices vertices;
	
	public Show(){
		
        shader = new Shader(Resources.getInputStream("glsl.vert"), Resources.getInputStream("glsl.frag"));       
        projection = new ProjectionMatrix();
        modelview = new Rotate(0, 0, 5);
        texture = new Texture2D(Handels.TEXTURE0, Resources.getInputStream("texture.png"));
        vertices = new Obj(Resources.getInputStream("car.obj"));
		
	}
	
	@Override 
	public void init(final GLAutoDrawable drawable) {
			
		shader.init(drawable);
		projection.init(drawable);
		modelview.init(drawable);
		texture.init(drawable);
		vertices.init(drawable);
		
	}
	
    @Override
    public void display(final GLAutoDrawable drawable) {
    	
		modelview.update();   	
    	
    	shader.bind();
    	projection.bind();
    	modelview.bind();
    	texture.bind();
    	
    	vertices.draw();
    	
    }

}
```


Ich hab mal ein Beispiel zusammengebaut, wie ich Deinen Code oben schreiben würde (in etwa). (Ich hab auch wieder ImageIO statt TextureIO genommen, Deine Texturklasse geht aber genauso gut!)

http://too-late.de/kskb/gl2sample03.zip

Wie immer:
Eclipse -> File -> Import -> General -> Existing Projects into Workspace -> Select archive file -> Browse -> gl2sample03.zip auswählen -> Öffnen -> Finish


Gruß,
Fancy


----------



## Developer_X (15. Nov 2009)

danke,
ich hab jetzt auch noch die Klasse GLUT etwas besser kennengelernt, sie kann für mich auch sehr viel übernehmen, zum beispiel glut.glutSolidCube oder oder oder.
Ich schau mir jetzt mal dein Beispiel an, danke, 
Developer_X


----------



## Developer_X (15. Nov 2009)

Eine frage habe ich jetzt aber noch.

Ich bin gerade dabei eine Art Hemisphere("HalbKugel") eher ein Halbcylinder aus dem Buchstaben M zu machen.


```
//Hairs
		float rot = 90;
		while(rot<=170)
		{
			gl.glTranslatef(0, -2,0);
			gl.glRotatef(+rot,0,1,0);
			
			gl.glTranslatef(0,0,-2);
			g.drawText(gl, glut, Color.red, "M");
			gl.glTranslatef(0,0,+2);

			gl.glRotatef(-rot,0,1,0);
			rot+=20;
			gl.glTranslatef(0,2,0);
		}
```
Das habe ich jetzt eingebaut, die methode drawText sieht so aus:

```
public void drawText(GL2 gl,GLUT glut, Color color, String text)
	{
		gl.glTranslatef((float)(-text.length()/2),0,0);
		char c;
		boolean lightingState;
		gl.glPushMatrix();
	 	float height = glut.glutStrokeLengthf(GLUT.STROKE_ROMAN, "X");
	 	float factor = 1.0f / height;
		gl.glScaled(factor, factor, factor);
		lightingState = gl.glIsEnabled(GL2.GL_LIGHTING);
		gl.glDisable(GL2.GL_LIGHTING);
	 	gl.glColor3d(color.getRed() / 255.0, color.getGreen() / 255.0, color.getBlue() / 255.0);
	 	gl.glLineWidth(3.0f);
	        
		for (int offset = 0; offset < text.length(); offset++) 
		{
			c = text.charAt(offset);
			glut.glutStrokeCharacter(GLUT.STROKE_ROMAN, c);
		}
		if (lightingState)
		{
			gl.glEnable(GL2.GL_LIGHTING);
		}
		gl.glTranslatef((float)(text.length()/2),0,0);
		
	 	gl.glLineWidth(1.0f);
	}
```
Das GLUT Objekt, wird in den Attributen instanziert, also bei der Klasse vom ersten Code Stück.

Wenn ich das ganze starte, sehe ich aber leider nur ein M.
Ich hab vor, hinter und in die schleife ausgaben gesetzt, 
ich denke das Problem liegt darin dass ich keine mehreren text schreiben kann?


----------



## Guest2 (15. Nov 2009)

Developer_X hat gesagt.:


> sehr viel übernehmen, zum beispiel glut.glutSolidCube



Ja, die glutSolid* kenne ich. Jedoch, ich zitiere mal aus der Dokumentation (11 Geometric Object Rendering):



> The routines generate normals appropriate for lighting but do not generate texture coordinates (except for the teapot).



Damit kannst Du die entsprechenden Geometrien zwar darstellen und beleuchten, jedoch keine Textur auflegen (außer eben bei der Teekanne)!  (x, y, z, nx, ny, nz werden erzeugt / s, t nicht)

Das ist auch einer der Grunde, warum ich früher schon mal schrieb, das man in OpenGL praktisch alles aus Dreiecken zusammenbaut. So rein aus dem Bauch heraus, würde ich vermuten, das Du zur Zeit versuchst den Rayman aus fertigen Objekten / Geometrien / Buchstaben zu bauen (ihmo hast Du das bei Java3D ja auch mal gemacht). Das kann eine gute Fingerübung sein (darum solltest Du das auch ruhig erstmal weitermachen!), aber schon mal vorweg, praktisch macht man das in OpenGL so nicht.   



Developer_X hat gesagt.:


> Wenn ich das ganze starte, sehe ich aber leider nur ein M.
> Ich hab vor, hinter und in die schleife ausgaben gesetzt,
> ich denke das Problem liegt darin dass ich keine mehreren text schreiben kann?



Nein, Du siehst schon alle Deine M's, ab dem zweiten M sind Sie nur viel zu klein als das man sie erkennen könnte.



Developer_X hat gesagt.:


> ```
> float factor = 1.0f / height;
> gl.glScaled(factor, factor, factor);
> ```



Genau da liegt der Fehler. OpenGL ist eine Zustandsmaschine, das heißt alles was Du einmal setzt wirkt sich auch auf die Zukunft aus. Hier ist Faktor kleiner 1, also wird alles nachfolgende verkleinert dargestellt. Nun rufst Du diese Funktion mehrmals auf, darum sind Deine M's viel zu klein. 

Am Anfang der Methode drawText() rufst Du  gl.glPushMatrix() auf. Setze einfach am Ende von drawText() noch das passende gl.glPopMatrix(), dann geht es.

Gruß,
Fancy


----------



## Developer_X (15. Nov 2009)

danke
Aber ich mach hier was anderes als Rayman.
Du wirst es schon noch mitbekommen und sehen.
^^
Wird echt witzig wenns klappt wie ich mirs vorgestellt habe.

DX


----------

