Author Topic: Texturing a triangle  (Read 6298 times)

Offline brunotrodrigues

  • byte
  • *
  • Posts: 20
    • View Profile
Texturing a triangle
« on: April 18, 2012, 10:42:42 pm »
Guys, I'm trying to texture the triangle faces of a rhombus with this code:

Code: [Select]
public Object3D buildMarker(){
Object3D mrkr = new Object3D(8);
mrkr.setCulling(false);
float offset = MARKER_SIZE/2;

mrkr.addTriangle(new SimpleVector(-offset, 0,-offset), 0, 1,
new SimpleVector( offset, 0,-offset), 1, 1,
new SimpleVector( 0,-MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector( offset, 0,-offset), 0, 1,
new SimpleVector( offset, 0, offset), 1, 1,
new SimpleVector( 0,-MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector( offset, 0, offset), 0, 1,
new SimpleVector(-offset, 0, offset), 1, 1,
new SimpleVector( 0,-MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector(-offset, 0, offset), 0, 1,
new SimpleVector(-offset, 0,-offset), 1, 1,
new SimpleVector( 0,-MARKER_SIZE, 0), 0.5f, 0);

mrkr.addTriangle(new SimpleVector( offset, 0,-offset), 0, 1,
new SimpleVector(-offset, 0,-offset), 1, 1,
new SimpleVector( 0,MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector( offset, 0, offset), 0, 1,
new SimpleVector( offset, 0,-offset), 1, 1,
new SimpleVector( 0,MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector(-offset, 0, offset), 0, 1,
new SimpleVector( offset, 0, offset), 1, 1,
new SimpleVector( 0,MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector(-offset, 0,-offset), 0, 1,
new SimpleVector(-offset, 0, offset), 1, 1,
new SimpleVector( 0,MARKER_SIZE, 0), 0.5f, 0);
return mrkr;
}

The Object3D structure is fine, but I'm positive my U/V-coordinates are wrong because it is not showing it how I expected.
The texture is a 128x128 black png with a transparent triangle with its base running along the base of the picture and its top touching the middle of the picture's top border (sorry, I can't upload it right now). I wanna make a red, wireframed rhombus.
This is how I'm adding the textures I use to the TextureManager tm:

Code: [Select]
tm.addTexture("frame", new Texture("markerFrame.png"));
tm.addTexture("red", new Texture(8,8,java.awt.Color.RED));

And this is how I Multi-texture them:

Code: [Select]
tInfo = new TextureInfo(tm.getTextureID("frame"));
tInfo.add(tm.getTextureID("red"), TextureInfo.MODE_ADD);

Help, please!

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Texturing a triangle
« Reply #1 on: April 20, 2012, 08:15:25 pm »
And the result is... ??? You have to choose the texture coordinates in a way that in texture space (i.e. when projecting the triangle onto the texture), the coordinates actually do make sense.  Just draw it on paper. It's shouldn't be too hard to figure it out that way.

Offline brunotrodrigues

  • byte
  • *
  • Posts: 20
    • View Profile
Re: Texturing a triangle
« Reply #2 on: June 15, 2012, 03:55:56 pm »
(Sorry for reviving this, but I have been very busy and could not come back until now)

What is the (0,0) point in a texture image? The upper-left corner? Or the bottom-left one?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Texturing a triangle
« Reply #3 on: June 15, 2012, 05:24:08 pm »
I don't know from the top of my head. Just try it.

Offline brunotrodrigues

  • byte
  • *
  • Posts: 20
    • View Profile
Re: Texturing a triangle
« Reply #4 on: June 15, 2012, 09:12:37 pm »
I did! Tried all four corners as origin and nothing worked.
So you say my code seems ok, but I still can't texture it right.
I'm lost...

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Texturing a triangle
« Reply #5 on: June 15, 2012, 09:16:38 pm »
...what the result you are getting? Can you post a screen shot?

Offline brunotrodrigues

  • byte
  • *
  • Posts: 20
    • View Profile
Re: Texturing a triangle
« Reply #6 on: June 15, 2012, 09:32:05 pm »
« Last Edit: June 15, 2012, 09:37:18 pm by brunotrodrigues »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Texturing a triangle
« Reply #7 on: June 15, 2012, 09:57:22 pm »
Ok...and the texture looks like?

Offline brunotrodrigues

  • byte
  • *
  • Posts: 20
    • View Profile
Re: Texturing a triangle
« Reply #8 on: June 15, 2012, 10:02:43 pm »
I don't know if you'll be able to see it.
http://imageupload.org/en/file/229807/c-documents-and-settingsf142247desktoppen-driveprojetosjpctdogfightcomdogfightresmarkerframe2.png.html

It's a black image with a transparent triangle.
This is the external texture. The red in the first picture is a solid texture I made with tm.addTexture("red", new Texture(8,8,java.awt.Color.RED));
« Last Edit: June 15, 2012, 10:04:38 pm by brunotrodrigues »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Texturing a triangle
« Reply #9 on: June 15, 2012, 10:39:06 pm »
I tried your code and your texture and everything is fine:



Maybe you've left some calcTextureWrapping-methods in?

Offline brunotrodrigues

  • byte
  • *
  • Posts: 20
    • View Profile
Re: Texturing a triangle
« Reply #10 on: June 15, 2012, 10:53:28 pm »
WTF!!!

No, I did not use calcTextureWrapping-methods (at least not that I know of).

Here is my full class:

Code: [Select]
package com.dogfight.util;

import java.awt.Color;

import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureInfo;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;

public class Unit extends Object3D{

private final float MARKER_SIZE = 20.0f;
private final float ROTATION_SPEED = 0.03f;
private Object3D marker = null;
private Object3D heightLine = null;

private TextureInfo tInfo = null;

public Unit(World world, String texture){
super(16);
TextureManager tm = TextureManager.getInstance();
tInfo = new TextureInfo(tm.getTextureID("frame"));
tInfo.add(tm.getTextureID(texture), TextureInfo.MODE_ADD);

marker = buildMarker();
marker.setTexture(tInfo);
marker.calcNormals();
marker.setTransparency(0);
marker.setLighting(LIGHTING_NO_LIGHTS);
marker.setAdditionalColor(Color.WHITE);

world.addObject(marker);
addChild(marker);
}

public Object3D buildMarker(){
Object3D mrkr = new Object3D(8);
mrkr.setCulling(false);
float offset = MARKER_SIZE/2;

mrkr.addTriangle(new SimpleVector(-offset, 0,-offset), 0, 1,
new SimpleVector( offset, 0,-offset), 1, 1,
new SimpleVector( 0,-MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector( offset, 0,-offset), 0, 1,
new SimpleVector( offset, 0, offset), 1, 1,
new SimpleVector( 0,-MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector( offset, 0, offset), 0, 1,
new SimpleVector(-offset, 0, offset), 1, 1,
new SimpleVector( 0,-MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector(-offset, 0, offset), 0, 1,
new SimpleVector(-offset, 0,-offset), 1, 1,
new SimpleVector( 0,-MARKER_SIZE, 0), 0.5f, 0);

mrkr.addTriangle(new SimpleVector( offset, 0,-offset), 0, 1,
new SimpleVector(-offset, 0,-offset), 1, 1,
new SimpleVector( 0,MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector( offset, 0, offset), 0, 1,
new SimpleVector( offset, 0,-offset), 1, 1,
new SimpleVector( 0,MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector(-offset, 0, offset), 0, 1,
new SimpleVector( offset, 0, offset), 1, 1,
new SimpleVector( 0,MARKER_SIZE, 0), 0.5f, 0);
mrkr.addTriangle(new SimpleVector(-offset, 0,-offset), 0, 1,
new SimpleVector(-offset, 0, offset), 1, 1,
new SimpleVector( 0,MARKER_SIZE, 0), 0.5f, 0);
return mrkr;
}

public Object3D createLine (SimpleVector point, float width, String textureName){
Object3D line = new Object3D( 8 );
float offset = width / 2.0f;
/*
// Quad A:
line.addTriangle( new SimpleVector( pointA.x-offset, pointA.y, pointA.z ), 0, 0,
new SimpleVector( pointA.x+offset, pointA.y, pointA.z ), 0, 1,
new SimpleVector( pointB.x+offset, pointB.y, pointB.z ), 1, 1,
TextureManager.getInstance().getTextureID( textureName ) );
line.addTriangle( new SimpleVector( pointB.x+offset, pointB.y, pointB.z ), 0, 0,
new SimpleVector( pointB.x-offset, pointB.y, pointB.z ), 0, 1,
new SimpleVector( pointA.x-offset, pointA.y, pointA.z ), 1, 1,
TextureManager.getInstance().getTextureID( textureName ) );
// Quad B:
line.addTriangle( new SimpleVector( pointA.x, pointA.y, pointA.z + offset ), 0, 0,
new SimpleVector( pointA.x, pointA.y, pointA.z - offset ), 0, 1,
new SimpleVector( pointB.x, pointB.y, pointB.z - offset ), 1, 1,
TextureManager.getInstance().getTextureID( textureName ) );
line.addTriangle( new SimpleVector( pointB.x, pointB.y, pointB.z - offset ), 0, 0,
new SimpleVector( pointB.x, pointB.y, pointB.z + offset ), 0, 1,
new SimpleVector( pointA.x, pointA.y, pointA.z + offset ), 1, 1,
TextureManager.getInstance().getTextureID( textureName ) );

// If you don't want the line to react to lighting:
line.setLighting( Object3D.LIGHTING_NO_LIGHTS );
line.setAdditionalColor(new java.awt.Color(0.2f,0.2f,0.2f));
line.setCulling(false);
*/
// done
return line;
}

public void update(){
//marker.rotateY(ROTATION_SPEED);
}
}

The declaration of the Red texture is in the main class, but there is no calcTextureWrapping there either.
I can post it here but I don't think that the problem is there.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Texturing a triangle
« Reply #11 on: June 15, 2012, 11:21:06 pm »
You are not calling build() as far as i can see. Replace marker.calcNormals(); with marker.build(); to see if that helps.

Offline brunotrodrigues

  • byte
  • *
  • Posts: 20
    • View Profile
Re: Texturing a triangle
« Reply #12 on: June 18, 2012, 03:57:42 pm »
Didn't work. Anything else? Want me to post the main class?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Texturing a triangle
« Reply #13 on: June 18, 2012, 04:41:58 pm »
...that might help.

Offline brunotrodrigues

  • byte
  • *
  • Posts: 20
    • View Profile
Re: Texturing a triangle
« Reply #14 on: June 18, 2012, 04:52:15 pm »
Code: [Select]
package com.dogfight;

import java.awt.Color;
import java.awt.event.KeyEvent;

import com.threed.jpct.Camera;
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.GenericVertexController;
import com.threed.jpct.GLSLShader;
import com.threed.jpct.IPaintListener;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Lights;
import com.threed.jpct.Loader;
import com.threed.jpct.Matrix;
import com.threed.jpct.Mesh;
import com.threed.jpct.Object3D;
import com.threed.jpct.PolygonManager;
import com.threed.jpct.Primitives;
import com.threed.jpct.Projector;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureInfo;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;

import com.threed.jpct.util.KeyMapper;
import com.threed.jpct.util.KeyState;
import com.threed.jpct.util.Light;
import com.threed.jpct.util.ShadowHelper;

//import org.lwjgl.input.*;

import com.dogfight.clientserver.*;
import com.dogfight.util.*;

public class Dogfight implements IPaintListener, GameClient {

private static final long serialVersionUID = 1L;

private static float PI = (float) Math.PI;

private KeyMapper keyMapper = null;
private MouseMapper mouseMapper = null;

private FrameBuffer buffer = null;

private World world = null;
private World sky = null;

private Object3D plane = null;
private Object3D snork = null;
private Object3D dome = null;
private Object3D dome2 = null;

private Unit unit = null;

private Light sun = null;

private ShadowHelper sh = null;
private Projector projector = null;

private float xAngle = 0;

private boolean forward = false;
private boolean backward = false;
private boolean up = false;
private boolean down = false;
private boolean left = false;
private boolean right = false;

private float ind = 0;
private boolean doLoop = true;
private int fps = 0;
private long time = System.currentTimeMillis();
private Ticker ticker = new Ticker(15);

public static void main(String[] args) throws Exception {
Config.glVerbose = true;
Dogfight cd = new Dogfight();
cd.init();
cd.initGUI();
cd.gameLoop();
}

public Dogfight() {
Config.glAvoidTextureCopies = true;
Config.maxPolysVisible = 1000;
Config.glColorDepth = 24;
Config.glFullscreen = false;
Config.farPlane = 2000000;
Config.glShadowZBias = 0.8f;
Config.lightMul = 1;
Config.collideOffset = 500;
Config.glTrilinear = true;
Config.mipmap = true;
}

public void finishedPainting() {
fps++;
}

public void startPainting() {
}

public void quit(){
}

public boolean runsServer(){
return true;
}

public void shutDownServer(){
}

public void startServer(int port){
}

public ServerEntry getServer(){
return null;
}

public boolean isConnected(){
return true;
}

public void disconnect(){
}

public void connect(ServerEntry server, String name){
}

private void init() throws Exception {

// Load textures

TextureManager tm = TextureManager.getInstance();
tm.addTexture("cyan", new Texture(8,8,java.awt.Color.CYAN));
tm.addTexture("red", new Texture(8,8,java.awt.Color.RED));
tm.addTexture("grass", new Texture("com/dogfight/example/GrassSample2.jpg"));
tm.addTexture("disco", new Texture("com/dogfight/example/disco.jpg"));
tm.addTexture("normals", new Texture("com/dogfight/example/normals.jpg"));
tm.addTexture("sky", new Texture("com/dogfight/res/sky.jpg"));
tm.addTexture("frame", new Texture("com/dogfight/res/markerFrame2.png"));
tm.addTexture("starfield", new Texture("com/dogfight/res/starfield.png"));

// Initialize frame buffer

buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_NORMAL);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL, IRenderer.MODE_OPENGL);
buffer.setPaintListener(this);

// Initialize worlds

world = new World();
world.setAmbientLight(80, 80, 80);
sky = new World();
sky.setAmbientLight(255, 255, 255);

world.getLights().setRGBScale(Lights.RGB_SCALE_2X);
sky.getLights().setRGBScale(Lights.RGB_SCALE_2X);
world.getLights().setOverbrightLighting(Lights.OVERBRIGHT_LIGHTING_ENABLED );
sky.getLights().setOverbrightLighting(Lights.OVERBRIGHT_LIGHTING_ENABLED );

// Initialize mappers

keyMapper = new KeyMapper();
mouseMapper = new MouseMapper(buffer);
mouseMapper.hide();

// Load/create and setup objects

plane = Primitives.getPlane(40, 60);
plane.rotateX(PI / 2f);
plane.setSpecularLighting(true);
plane.setTexture("grass");
plane.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);

unit = new Unit(world, "red");
unit.translate(0,-100,-20);

snork = Loader.loadMD2("com/dogfight/example/snork.md2", 0.8f);
snork.translate(0, -25, -50);
snork.setTexture("disco");

dome = Object3D.mergeAll(Loader.load3DS("com/dogfight/res/sphere.3ds", 2000.0f));
dome.build();
dome.rotateX(-PI / 2f);
dome.setTexture("starfield");
dome.translate(plane.getTransformedCenter().calcSub(dome.getTransformedCenter()));
dome.setLighting(Object3D.LIGHTING_NO_LIGHTS);

// Add objects to the worlds

world.addObject(plane);
world.addObject(snork);
world.addObject(unit);
sky.addObject(dome);

// Build all world's objects

world.buildAllObjects();

// Compile all objects for better performance

plane.compileAndStrip();
dome.compileAndStrip();

snork.compile(true, true, true, false, 2000);
snork.setCollisionMode(Object3D.COLLISION_CHECK_SELF);

unit.compile(true, true, true, false, 2000);
unit.setCollisionMode(Object3D.COLLISION_CHECK_SELF);

// Deform the plane

Mesh planeMesh = plane.getMesh();
planeMesh.setVertexController(new Mod(), false);
planeMesh.applyVertexController();
planeMesh.removeVertexController();

// Initialize shadow helper

projector = new Projector();
projector.setFOV(1.5f);
projector.setYFOV(1.5f);

sh = new ShadowHelper(world, buffer, projector, 2048);
sh.setCullingMode(false);
sh.setAmbientLight(new Color(80, 80, 80));
sh.setLightMode(true);
sh.setBorder(0);

sh.addCaster(snork);
sh.addCaster(unit);

sh.addReceiver(plane);

// Setup dynamic light source

sun = new Light(world);
sun.setIntensity(250, 250, 250);
sun.setAttenuation(800);

// Setup shaders for the rock

String fragmentShader = Loader.loadTextFile("com/dogfight/example/shader/fragmentshader.glsl");
String vertexShader = Loader.loadTextFile("com/dogfight/example/shader/vertexshader.glsl");

GLSLShader shader = new GLSLShader(vertexShader, fragmentShader);
shader.setShadowHelper(sh);
shader.setStaticUniform("colorMap", 0);
shader.setStaticUniform("normalMap", 1);
shader.setStaticUniform("invRadius", 0.0005f);
//rock.setRenderHook(shader);

// Move camera

Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 2000);
cam.moveCamera(Camera.CAMERA_MOVEUP, 1000);
cam.lookAt(plane.getTransformedCenter());
cam.setFOV(1.5f);
}

private void initGUI(){

}

private void drawGUI(){

}

private void pollControls() {

KeyState ks = null;
while ((ks = keyMapper.poll()) != KeyState.NONE) {
if (ks.getKeyCode() == KeyEvent.VK_ESCAPE) {
doLoop = false;
}

if (ks.getKeyCode() == KeyEvent.VK_UP) {
forward = ks.getState();
}

if (ks.getKeyCode() == KeyEvent.VK_DOWN) {
backward = ks.getState();
}

if (ks.getKeyCode() == KeyEvent.VK_LEFT) {
left = ks.getState();
}

if (ks.getKeyCode() == KeyEvent.VK_RIGHT) {
right = ks.getState();
}

if (ks.getKeyCode() == KeyEvent.VK_PAGE_UP) {
up = ks.getState();
}

if (ks.getKeyCode() == KeyEvent.VK_PAGE_DOWN) {
down = ks.getState();
}
}

if (org.lwjgl.opengl.Display.isCloseRequested()) {
doLoop = false;
}
}

private void move(long ticks) {

if (ticks == 0) {
return;
}

// Key controls

SimpleVector ellipsoid = new SimpleVector(5, 5, 5);

if (forward) {
world.checkCameraCollisionEllipsoid(Camera.CAMERA_MOVEIN, ellipsoid, ticks*5, 5);
}

if (backward) {
world.checkCameraCollisionEllipsoid(Camera.CAMERA_MOVEOUT, ellipsoid, ticks*5, 5);
}

if (left) {
world.checkCameraCollisionEllipsoid(Camera.CAMERA_MOVELEFT, ellipsoid, ticks*5, 5);
}

if (right) {
world.checkCameraCollisionEllipsoid(Camera.CAMERA_MOVERIGHT, ellipsoid, ticks*5, 5);
}

if (up) {
world.checkCameraCollisionEllipsoid(Camera.CAMERA_MOVEUP, ellipsoid, ticks*5, 5);
}

if (down) {
world.checkCameraCollisionEllipsoid(Camera.CAMERA_MOVEDOWN, ellipsoid, ticks*5, 5);
}

// mouse rotation

Matrix rot = world.getCamera().getBack();
int dx = mouseMapper.getDeltaX();
int dy = mouseMapper.getDeltaY();

float ts = 0.2f * ticks;
float tsy = ts;

if (dx != 0) {
ts = dx / 500f;
}
if (dy != 0) {
tsy = dy / 500f;
}

if (dx != 0) {
rot.rotateAxis(rot.getYAxis(), ts);
}

if ((dy > 0 && xAngle < Math.PI / 1.6)
|| (dy < 0 && xAngle > -Math.PI / 3.2)) {
rot.rotateX(tsy);
xAngle += tsy;
}

// Update the skydome

sky.getCamera().setBack(world.getCamera().getBack().cloneMatrix());
dome.rotateY(0.00005f * ticks);
}

private void gameLoop() throws Exception {

SimpleVector pos = snork.getTransformedCenter();
SimpleVector offset = new SimpleVector(1, 0,-1).normalize();

long ticks = 0;

while (doLoop) {

ticks = ticker.getTicks();

if (ticks > 0) {
// animate the snork and the dome

animate(ticks);
unit.update();
offset.rotateY(0.007f * ticks);

// move the camera

pollControls();
move(ticks);
drawGUI();
}

// update the projector for the shadow map

projector.lookAt(plane.getTransformedCenter());
projector.setPosition(pos);
projector.moveCamera(new SimpleVector(0, -1, 0), 200);
projector.moveCamera(offset, 215);
sun.setPosition(projector.getPosition());

// update the shadow map

sh.updateShadowMap();

// render the scene

buffer.clear();

buffer.setPaintListenerState(false);
sky.renderScene(buffer);
sky.draw(buffer);
buffer.setPaintListenerState(true);
sh.drawScene();
buffer.update();
buffer.displayGLOnly();

// print out the fps to the console

if (System.currentTimeMillis() - time >= 1000) {
System.out.println(fps);
fps = 0;
time = System.currentTimeMillis();
}
}

// exit...

System.exit(0);
}

// note: you will need to define a texture ahead of time.  For a solid-color line, you could use something like:
// TextureManager.getInstance().addTexture( "Red", new Texture( 8, 8, java.awt.Color.Red ) );

public Object3D createLine (SimpleVector pointA, SimpleVector pointB, float width, String textureName){
Object3D line = new Object3D( 8 );
float offset = width / 2.0f;

// Quad A:
line.addTriangle( new SimpleVector( pointA.x-offset, pointA.y, pointA.z ), 0, 0,
new SimpleVector( pointA.x+offset, pointA.y, pointA.z ), 0, 1,
new SimpleVector( pointB.x+offset, pointB.y, pointB.z ), 1, 1,
TextureManager.getInstance().getTextureID( textureName ) );
line.addTriangle( new SimpleVector( pointB.x+offset, pointB.y, pointB.z ), 0, 0,
new SimpleVector( pointB.x-offset, pointB.y, pointB.z ), 0, 1,
new SimpleVector( pointA.x-offset, pointA.y, pointA.z ), 1, 1,
TextureManager.getInstance().getTextureID( textureName ) );
// Quad B:
line.addTriangle( new SimpleVector( pointA.x, pointA.y, pointA.z + offset ), 0, 0,
new SimpleVector( pointA.x, pointA.y, pointA.z - offset ), 0, 1,
new SimpleVector( pointB.x, pointB.y, pointB.z - offset ), 1, 1,
TextureManager.getInstance().getTextureID( textureName ) );
line.addTriangle( new SimpleVector( pointB.x, pointB.y, pointB.z - offset ), 0, 0,
new SimpleVector( pointB.x, pointB.y, pointB.z + offset ), 0, 1,
new SimpleVector( pointA.x, pointA.y, pointA.z + offset ), 1, 1,
TextureManager.getInstance().getTextureID( textureName ) );

// If you don't want the line to react to lighting:
line.setLighting( Object3D.LIGHTING_NO_LIGHTS );
line.setAdditionalColor(new java.awt.Color(0.2f,0.2f,0.2f));
line.setCulling(false);

// done
return line;
}

private void animate(long ticks) {
if (ticks > 0) {
float ft = (float) ticks;
ind += 0.02f * ft;
if (ind > 1) {
ind -= 1;
}
snork.animate(ind, 2);
snork.rotateY(-0.02f * ft);
snork.translate(0, -50, 0);
SimpleVector dir = snork.getXAxis();
dir.scalarMul(ft);
dir = snork.checkForCollisionEllipsoid(dir, new SimpleVector(5, 20, 5), 5);
snork.translate(dir);
dir = snork.checkForCollisionEllipsoid(new SimpleVector(0, 100, 0), new SimpleVector(5, 20, 5), 1);
snork.translate(dir);
}
}

private void tileTexture(Object3D obj, float tileFactor) {
PolygonManager pm = obj.getPolygonManager();

int end = pm.getMaxPolygonID();
for (int i = 0; i < end; i++) {
SimpleVector uv0 = pm.getTextureUV(i, 0);
SimpleVector uv1 = pm.getTextureUV(i, 1);
SimpleVector uv2 = pm.getTextureUV(i, 2);

uv0.scalarMul(tileFactor);
uv1.scalarMul(tileFactor);
uv2.scalarMul(tileFactor);

int id = pm.getPolygonTexture(i);

TextureInfo ti = new TextureInfo(id, uv0.x, uv0.y, uv1.x, uv1.y,
uv2.x, uv2.y);
pm.setPolygonTexture(i, ti);
}
}

private static class Mod extends GenericVertexController {
private static final long serialVersionUID = 1L;

public void apply() {
SimpleVector[] s = getSourceMesh();
SimpleVector[] d = getDestinationMesh();
for (int i = 0; i < s.length; i++) {
d[i].z = s[i].z
- (10f * ((float) Math.sin(s[i].x / 50f) + (float) Math.cos(s[i].y / 50f)));
d[i].x = s[i].x;
d[i].y = s[i].y;
}
}
}

private static class Ticker {

private int rate;
private long s2;

public static long getTime() {
return System.currentTimeMillis();
}

public Ticker(int tickrateMS) {
rate = tickrateMS;
s2 = Ticker.getTime();
}

public int getTicks() {
long i = Ticker.getTime();
if (i - s2 > rate) {
int ticks = (int) ((i - s2) / (long) rate);
s2 += (long) rate * ticks;
return ticks;
}
return 0;
}
}
}