/**
* Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.codesourcery.jasm16.utils;
import java.text.DecimalFormat;
public final class Vector4
{
private float[] data;
private int offset=0;
public Vector4(Vector4 input)
{
data = new float[4];
input.copyInto( data , 0 );
}
public int toRGB() {
int color = ((int) ( r() *255f) ) << 16;
color |= ((int) ( g() *255f) ) << 8;
color |= ((int) ( b() *255f) );
return color;
}
public Vector4() {
data = new float[4];
}
public Vector4(float[] data) {
this.data = data;
}
public void setData(float[] data,int offset) {
this.data = data;
this.offset = offset;
}
public void copyFrom(Vector4 other)
{
final int otherOffset = other.getDataOffset();
final float[] otherData = other.getDataArray();
this.data[offset] = otherData[ otherOffset ];
this.data[offset+1] = otherData[ otherOffset+1 ];
this.data[offset+2] = otherData[ otherOffset+2 ];
this.data[offset+3] = otherData[ otherOffset+3 ];
}
public void copyInto(float[] array,int startingOffset)
{
array[startingOffset] = this.data[offset];
array[startingOffset+1] = this.data[offset+1];
array[startingOffset+2] = this.data[offset+2];
array[startingOffset+3] = this.data[offset+3];
}
public Vector4(float[] data,int offset)
{
this.data = data;
this.offset = offset;
}
public boolean isEquals(Vector4 other) {
return this.x() == other.x() &&
this.y() == other.y() &&
this.z() == other.z() &&
this.w() == other.w();
}
public void x(float value) {
this.data[ offset ] = value;
}
public void r(float value) {
this.data[ offset ] = value;
}
public void y(float value) {
this.data[ offset +1 ] = value;
}
public void g(float value) {
this.data[ offset +1 ] = value;
}
public void z(float value) {
this.data[ offset +2 ] = value;
}
public void b(float value) {
this.data[ offset +2 ] = value;
}
public void w(float value) {
this.data[ offset + 3 ] = value;
}
public void a(float value) {
this.data[ offset + 3 ] = value;
}
public float x() {
return this.data[ offset ];
}
public float r() {
return this.data[ offset ];
}
public float y() {
return this.data[ offset + 1 ];
}
public float g() {
return this.data[ offset + 1 ];
}
public float z() {
return this.data[ offset + 2 ];
}
public float b() {
return this.data[ offset + 2 ];
}
public float w() {
return this.data[ offset + 3];
}
public float a() {
return this.data[ offset + 3];
}
public Vector4 minus(Vector4 other)
{
// TODO: Maybe it's faster to use a loop here ? Needs benchmarking
return new Vector4( this.x() - other.x() , this.y() - other.y() , this.z() - other.z() , w() );
}
public float distanceTo(Vector4 point)
{
float x = this.x() - point.x();
float y = this.y() - point.y();
float z = this.z() - point.z();
return (float) Math.sqrt( x*x + y*y + z*z );
}
public Vector4 plus(Vector4 other) {
// TODO: Maybe it's faster to use a loop here ? Needs benchmarking
return new Vector4( this.x() + other.x() , this.y() + other.y() , this.z() + other.z() , w() );
}
public Vector4(float x,float y,float z) {
this(x,y,z,1);
}
public Vector4(float x,float y,float z,float w)
{
this.data = new float[] { x , y , z , w };
}
public Vector4 multiply( Matrix matrix)
{
final float[] result = new float[4];
final float[] thisData = this.data;
final float[] matrixData = matrix.getData();
final int offset = this.offset;
result[0] = thisData[ offset ] * matrixData[0] + thisData[offset+1] * matrixData[1]+
thisData[offset+2] * matrixData[2]+ thisData[offset+3] * matrixData[3];
result[1] = thisData[ offset ] * matrixData[4] + thisData[offset+1] * matrixData[5] +
thisData[offset+2] * matrixData[6] + thisData[offset+3] * matrixData[7];
result[2] = thisData[ offset ] * matrixData[8] + thisData[offset+1] * matrixData[9] +
thisData[offset+2] * matrixData[10] + thisData[offset+3] * matrixData[11];
result[3] = thisData[ offset ] * matrixData[12] + thisData[offset+1] * matrixData[13] +
thisData[offset+2] * matrixData[14] + thisData[offset+3] * matrixData[15];
return new Vector4( result );
}
public float[] getDataArray()
{
return data;
}
public int getDataOffset()
{
return offset;
}
public float length()
{
return (float) Math.sqrt( x()*x() + y()*y() + z()*z() );
}
public Vector4 multiply(float value)
{
return new Vector4( x()*value , y()*value , z()*value , w() );
}
public Vector4 normalize()
{
final float len = length();
if ( len == 0 ) {
return new Vector4(0,0,0);
}
return new Vector4( x() / len , y() / len , z() / len , w() );
}
public void normalizeInPlace()
{
final float len = length();
if ( len != 0 && len != 1 )
{
this.data[offset] = this.data[offset] / len;
this.data[offset+1] = this.data[offset+1] / len;
this.data[offset+2] = this.data[offset+2] / len;
}
}
public Vector4 normalizeW()
{
float w = w();
if ( w != 1.0 )
{
return new Vector4( x() / w, y() / w , z() / w , 1 );
}
return this;
}
public void normalizeWInPlace()
{
float w = w();
if ( w != 1.0 )
{
x( x() / w );
y( y() / w );
z( z() / w );
}
}
// scalar / dot product
public float dotProduct(Vector4 o)
{
return data[offset]*o.data[o.offset] + data[offset+1]*o.data[o.offset+1]+data[offset+2]*o.data[o.offset+2];
}
public float angleInRadians(Vector4 o) {
// => cos
final float cosine = dotProduct( o ) / ( length() * o.length() );
return (float) Math.acos( cosine );
}
public float angleInDegrees(Vector4 o) {
final float factor = (float) (180.0f / Math.PI);
return angleInRadians(o)*factor;
}
public Vector4 crossProduct(Vector4 other)
{
final float[] thisData = this.data;
final int thisOffset = this.offset;
final float[] o = other.data;
final int oOffset = other.offset;
final float x1 = thisData[thisOffset];
final float y1 = thisData[thisOffset+1];
final float z1 = thisData[thisOffset+2];
final float x2 = o[ oOffset ];
final float y2 = o[ oOffset+1 ];
final float z2 = o[ oOffset+2 ];
float newX = y1 * z2 - y2 * z1;
float newY = z1 * x2 - z2 * x1;
float newZ = x1 * y2 - x2 * y1;
return new Vector4( newX ,newY,newZ );
}
@Override
public String toString()
{
return "("+format( x() ) +","+format( y() ) +","+format( z() )+","+format( w() )+")";
}
private static String format(float d) {
return new DecimalFormat("##0.0###").format( d );
}
}