Overloading of operator.

New to FreeBASIC? Post your questions here.
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

Overloading of operator.

Postby podvornyak » Sep 06, 2013 15:50

Is there a better way to overload * operator, in this case?.. without temporal variable defination? Cause - if operator * can assume this "operator = whatever", why it can't assume kind a this one "operator.variable = whatever.variable"?

Code: Select all

type UDT
   as single ptr data
   declare constructor
   declare destructor
   declare operator let(as UDT)
end type
constructor UDT
   this.data = allocate(4)
end constructor
destructor UDT
   deallocate this.data
end destructor

operator UDT.let(rhs as UDT)
   this.data[0] = rhs.data[0]
end operator

' is it correct at least?
operator * (lhs as UDT, rhs as UDT) as UDT
   dim as UDT result
   result.data[0] = lhs.data[0] * rhs.data[0]
   operator = result
end operator
'

dim as UDT udt1, udt2, udt3
udt1.data[0]=2
udt2.data[0]=4

udt3=udt1*udt2

print udt3.data[0]

I'm starting to suspect that functional approach is more efficient than oop, in all cases.
fxm
Posts: 8959
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Overloading of operator.

Postby fxm » Sep 06, 2013 18:25

The code is good (including the * operator body).
You have well defined a default constructor and a let operator which both are mandatory to a correct working of your above program (the implicit constructor and the implicit let operator generated by the compiler would be false).
In addition, if you want to be compatible of using the keyword return in the * operator body or execute a copy-construction for the udt3 object, it is also mandatory to define a copy-constructor (the implicit copy-constructor generated by the compiler would be also false).

A variant with also defined a copy-constructor, and its use:

Code: Select all

type UDT
   as single ptr data
   declare constructor
   declare constructor (as UDT)
   declare destructor
   declare operator let(as UDT)
end type
constructor UDT
   this.data = allocate(1*sizeof(single))
end constructor
constructor UDT (rhs as UDT)
   this.data = allocate(1*sizeof(single))
   this = rhs
end constructor
destructor UDT
   deallocate this.data
end destructor

operator UDT.let(rhs as UDT)
   this.data[0] = rhs.data[0]
end operator

' is it correct at least?
operator * (lhs as UDT, rhs as UDT) as UDT
   dim as UDT result
   result.data[0] = lhs.data[0] * rhs.data[0]
   return result
end operator
'

dim as UDT udt1, udt2
udt1.data[0]=2
udt2.data[0]=4

dim as UDT udt3=udt1*udt2

print udt3.data[0]
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

Re: Overloading of operator.

Postby podvornyak » Sep 06, 2013 20:27

fxm wrote:... compatible ...

Than you for the tip. It is clear now - why... Anyway. I've changed my mind. Price of this "comfort coding" and "clean code" is too high - twice speed loss - from 300 fps to 150 in my case. :(
dodicat
Posts: 5757
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Overloading of operator.

Postby dodicat » Sep 06, 2013 22:36

Yes podvornyak.
Nice code, but for what (I think) you are trying to do, going through constructors is a waste of time (literally).
I think you are using [~] elements instead of array (~) elements for matrix manipulations.

I tried out a set of constructors a while back for Bignumbers.
I made a type Bigfloat with associated constructors.
Doing something like a ^ operator I had to go through a * operator for type Bigfloat.
So 2^1000000 would end up 1000000 constructor calls, plus the actual multiply calls, a complete waste of time.
Pritchard
Posts: 5492
Joined: Sep 12, 2005 20:06
Location: Ohio, USA

Re: Overloading of operator.

Postby Pritchard » Sep 07, 2013 2:59

Yeah, it all depends on implementation. I mean, the compiler isn't going to do much optimization in this case. Halving FPS sounds a little dramatic, though. Dr_D and relsoft did plenty of operator overloading for their matrix operations and their were presenting 3D demos that ran just fine.
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

Re: Overloading of operator.

Postby podvornyak » Sep 07, 2013 5:10

Yes, guys. My implimentation isn't good. Probably, assembler can help with that, but i don't know it. I've just try to overload multiplication of vector with matrix and come to this... 200k vectors - 40 fps instead of 80. Indeed - waste of time. Also i've come to another problem of overloading - private member access. Any way - here the header i'm working on. I'm trying to make kind a translation of GLM header-only-library...

Code: Select all

type CLASS_VECTOR4
   declare constructor
   declare constructor(byref as CLASS_VECTOR4)
   declare destructor
   declare operator let(byref as CLASS_VECTOR4)
'   private:
      as single ptr data
end type
constructor CLASS_VECTOR4
   this.data = allocate(16) '4 * size of single
   this.data[0]=0: this.data[1]=0: this.data[2]=0: this.data[3]=1
end constructor
constructor CLASS_VECTOR4(byref rhs as CLASS_VECTOR4)
   this.data = allocate(16) '4 * size of single
   this = rhs
end constructor
destructor CLASS_VECTOR4
   deallocate this.data
end destructor
operator CLASS_VECTOR4.let(byref rhs as CLASS_VECTOR4)
   this.data[0] = rhs.data[0]
   this.data[1] = rhs.data[1]
   this.data[2] = rhs.data[2]
   this.data[3] = rhs.data[3]
end operator

type CLASS_MATRIX4X4
   declare constructor
   declare constructor(byref as CLASS_MATRIX4X4)
   declare destructor
   declare operator let(byref as CLASS_MATRIX4X4)
   declare sub translate(byref as single=0, byref as single=0, byref as single=0)
   declare sub rotate(byref as single=0, byref as single=0, byref as single=0)
   declare sub rotatex(byref as single)
   declare sub rotatey(byref as single)
   declare sub rotatez(byref as single)
   declare sub scale(byref as single=1, byref as single=1, byref as single=1)
'   private:
      as single ptr data
end type
constructor CLASS_MATRIX4X4
   this.data=allocate(64) '16 * size of single
   this.data[0]=1: this.data[1]=0: this.data[2]=0: this.data[3]=0
   this.data[4]=0: this.data[5]=1: this.data[6]=0: this.data[7]=0
   this.data[8]=0: this.data[9]=0: this.data[10]=1: this.data[11]=0
   this.data[12]=0: this.data[13]=0: this.data[14]=0: this.data[15]=1
end constructor
constructor CLASS_MATRIX4X4(rhs as CLASS_MATRIX4X4)
   this.data=allocate(64) '16 * size of single
   this = rhs
end constructor
destructor CLASS_MATRIX4X4
   if this.data then deallocate this.data
end destructor
operator CLASS_MATRIX4X4.let (byref rhs as CLASS_MATRIX4X4)
   this.data[0] = rhs.data[0]
   this.data[1] = rhs.data[1]
   this.data[2] = rhs.data[2]
   this.data[3] = rhs.data[3]
   this.data[4] = rhs.data[4]
   this.data[5] = rhs.data[5]
   this.data[6] = rhs.data[6]
   this.data[7] = rhs.data[7]
   this.data[8] = rhs.data[8]
   this.data[9] = rhs.data[9]
   this.data[10] = rhs.data[10]
   this.data[11] = rhs.data[11]
   this.data[12] = rhs.data[12]
   this.data[13] = rhs.data[13]
   this.data[14] = rhs.data[14]
   this.data[15] = rhs.data[15]
end operator
sub CLASS_MATRIX4X4.translate(byref x as single, byref y as single, byref z as single)
with this
   .data[0]=1:  .data[1]=0:  .data[2]=0:  .data[3]=  x
   .data[4]=0:  .data[5]=1:  .data[6]=0:  .data[7]=  y
   .data[8]=0:  .data[9]=0:  .data[10]=1: .data[11]= z
   .data[12]=0: .data[13]=0: .data[14]=0: .data[15]=1
end with   
end sub
sub CLASS_MATRIX4X4.rotate(byref x as single, byref y as single, byref z as single)
   dim as single cos_x=cos(x), sin_x=sin(x)
   dim as single cos_y=cos(y), sin_y=sin(y)
   dim as single cos_z=cos(z), sin_z=sin(z)

   this.data[0] = cos_y*cos_z: this.data[1] = -sin_z: this.data[2] = sin_y: this.data[3] = 0
   this.data[4] = sin_z: this.data[5] = cos_x*cos_z: this.data[6] = -sin_x:   this.data[7] = 0
   this.data[8] = -sin_y: this.data[9] = sin_x: this.data[10] = cos_x*cos_y: this.data[11] = 0
   this.data[12] = 0: this.data[13] = 0: this.data[14] = 0: this.data[15] = 1
end sub

sub CLASS_MATRIX4X4.rotatex(byref x as single)
   dim as single cos_x=cos(x), sin_x=sin(x)
   
   this.data[0] = 1:  this.data[1] = 0:     this.data[2] = 0:      this.data[3] = 0
   this.data[4] = 0:  this.data[5] = cos_x: this.data[6] = -sin_x: this.data[7] = 0
   this.data[8] = 0:  this.data[9] = sin_x: this.data[10] = cos_x: this.data[11] = 0
   this.data[12] = 0: this.data[13] = 0:    this.data[14] = 0:     this.data[15] = 1
end sub
sub CLASS_MATRIX4X4.rotatey(byref y as single)
   dim as single cos_y=cos(y), sin_y=sin(y)
   
   this.data[0] = cos_y:  this.data[1] = 0:  this.data[2] = sin_y:  this.data[3] = 0
   this.data[4] = 0:      this.data[5] = 1:  this.data[6] = 0:      this.data[7] = 0
   this.data[8] = -sin_y: this.data[9] = 0:  this.data[10] = cos_y: this.data[11] = 0
   this.data[12] = 0:     this.data[13] = 0: this.data[14] = 0:     this.data[15] = 1
end sub
sub CLASS_MATRIX4X4.rotatez(byref z as single)
   dim as single cos_z=cos(z), sin_z=sin(z)

   this.data[0] = cos_z: this.data[1] = -sin_z: this.data[2] = 0:  this.data[3] = 0
   this.data[4] = sin_z: this.data[5] = cos_z:  this.data[6] = 0:  this.data[7] = 0
   this.data[8] = 0:     this.data[9] = 0:      this.data[10] = 1: this.data[11] = 0
   this.data[12] = 0:    this.data[13] = 0:     this.data[14] = 0: this.data[15] = 1
end sub
sub CLASS_MATRIX4X4.scale(byref x as single, byref y as single, byref z as single)
   this.data[0]=x: this.data[1]=0: this.data[2]=0: this.data[3]=0
   this.data[4]=0: this.data[5]=y: this.data[6]=0: this.data[7]=0
   this.data[8]=0: this.data[9]=0: this.data[10]=z: this.data[11]=0
   this.data[12]=0: this.data[13]=0: this.data[14]=0: this.data[15]=1
end sub

' multiply matrix with matrix
dim shared as CLASS_MATRIX4X4 _M4xM4
operator * (byref lhs as CLASS_MATRIX4X4, byref rhs as CLASS_MATRIX4X4) as CLASS_MATRIX4X4
   _M4xM4.data[0] = lhs.data[0]*rhs.data[0]   + lhs.data[1]*rhs.data[4]  + lhs.data[2]*rhs.data[8]   + lhs.data[3]*rhs.data[12]
   _M4xM4.data[1] = lhs.data[0]*rhs.data[1]   + lhs.data[1]*rhs.data[5]  + lhs.data[2]*rhs.data[9]   + lhs.data[3]*rhs.data[13]
   _M4xM4.data[2] = lhs.data[0]*rhs.data[2]   + lhs.data[1]*rhs.data[6]  + lhs.data[2]*rhs.data[10]  + lhs.data[3]*rhs.data[14]
   _M4xM4.data[3] = lhs.data[0]*rhs.data[3]   + lhs.data[1]*rhs.data[7]  + lhs.data[2]*rhs.data[11]  + lhs.data[3]*rhs.data[15]

   _M4xM4.data[4] = lhs.data[4]*rhs.data[0]   + lhs.data[5]*rhs.data[4]  + lhs.data[6]*rhs.data[8]   + lhs.data[7]*rhs.data[12]
   _M4xM4.data[5] = lhs.data[4]*rhs.data[1]   + lhs.data[5]*rhs.data[5]  + lhs.data[6]*rhs.data[9]   + lhs.data[7]*rhs.data[13]
   _M4xM4.data[6] = lhs.data[4]*rhs.data[2]   + lhs.data[5]*rhs.data[6]  + lhs.data[6]*rhs.data[10]  + lhs.data[7]*rhs.data[14]
   _M4xM4.data[7] = lhs.data[4]*rhs.data[3]   + lhs.data[5]*rhs.data[7]  + lhs.data[6]*rhs.data[11]  + lhs.data[7]*rhs.data[15]

   _M4xM4.data[8] = lhs.data[8]*rhs.data[0]   + lhs.data[9]*rhs.data[4]  + lhs.data[10]*rhs.data[8]  + lhs.data[11]*rhs.data[12]
   _M4xM4.data[9] = lhs.data[8]*rhs.data[1]   + lhs.data[9]*rhs.data[5]  + lhs.data[10]*rhs.data[9]  + lhs.data[11]*rhs.data[13]
   _M4xM4.data[10] = lhs.data[8]*rhs.data[2]  + lhs.data[9]*rhs.data[6]  + lhs.data[10]*rhs.data[10] + lhs.data[11]*rhs.data[14]
   _M4xM4.data[11] = lhs.data[8]*rhs.data[3]  + lhs.data[9]*rhs.data[7]  + lhs.data[10]*rhs.data[11] + lhs.data[11]*rhs.data[15]

   _M4xM4.data[12] = lhs.data[12]*rhs.data[0] + lhs.data[13]*rhs.data[4] + lhs.data[14]*rhs.data[8]  + lhs.data[15]*rhs.data[12]
   _M4xM4.data[13] = lhs.data[12]*rhs.data[1] + lhs.data[13]*rhs.data[5] + lhs.data[14]*rhs.data[9]  + lhs.data[15]*rhs.data[13]
   _M4xM4.data[14] = lhs.data[12]*rhs.data[2] + lhs.data[13]*rhs.data[6] + lhs.data[14]*rhs.data[10] + lhs.data[15]*rhs.data[14]
   _M4xM4.data[15] = lhs.data[12]*rhs.data[3] + lhs.data[13]*rhs.data[7] + lhs.data[14]*rhs.data[11] + lhs.data[15]*rhs.data[15]
   return _M4xM4
end operator

' multiply vector with matrix
dim shared as CLASS_VECTOR4 _V4xM4
operator * (byref lhs as CLASS_VECTOR4, byref rhs as CLASS_MATRIX4X4) as CLASS_VECTOR4
   _V4xM4.data[0] = lhs.data[0]*rhs.data[0]   + lhs.data[1]*rhs.data[1]  + lhs.data[2]*rhs.data[2]   + lhs.data[3]*rhs.data[3]
   _V4xM4.data[1] = lhs.data[0]*rhs.data[4]   + lhs.data[1]*rhs.data[5]  + lhs.data[2]*rhs.data[6]   + lhs.data[3]*rhs.data[7]
   _V4xM4.data[2] = lhs.data[0]*rhs.data[8]   + lhs.data[1]*rhs.data[9]  + lhs.data[2]*rhs.data[10]  + lhs.data[3]*rhs.data[11]
   _V4xM4.data[3] = lhs.data[0]*rhs.data[12]   + lhs.data[1]*rhs.data[13]  + lhs.data[2]*rhs.data[14]  + lhs.data[3]*rhs.data[15]
   return _V4xM4
end operator

' multiply vector with matrix through pointers
sub multiply_vector (result as single ptr, vector as single ptr, matrix as single ptr)
   result[0] = vector[0]*matrix[0]  + vector[1]*matrix[1]  + vector[2]*matrix[2]  + vector[3]*matrix[3]
   result[1] = vector[0]*matrix[4]  + vector[1]*matrix[5]  + vector[2]*matrix[6]  + vector[3]*matrix[7]
   result[2] = vector[0]*matrix[8]  + vector[1]*matrix[9]  + vector[2]*matrix[10] + vector[3]*matrix[11]
   result[3] = vector[0]*matrix[12] + vector[1]*matrix[13] + vector[2]*matrix[14] + vector[3]*matrix[15]
end sub

type as CLASS_MATRIX4X4 mat4
type as CLASS_VECTOR4 vec4

'matrix = matrix * matrix 'допустимо
'vector = vector * matrix 'недопустимо
fxm
Posts: 8959
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Overloading of operator.

Postby fxm » Sep 07, 2013 6:10

You can easily optimize the two let operators by calling the memcpy() C runtime function:

Code: Select all

#include "crt/string.bi"

'.....

operator CLASS_VECTOR4.let(byref rhs as CLASS_VECTOR4)
   memcpy(this.data, rhs.data, 16)
end operator

'.....

operator CLASS_MATRIX4X4.let (byref rhs as CLASS_MATRIX4X4)
   memcpy(this.data, rhs.data, 64)
end operator
fxm
Posts: 8959
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Overloading of operator.

Postby fxm » Sep 07, 2013 9:02

You have optimized the two * operators by declaring one global object instead of declare a local object at each call.
Following this, from fbc version 0.90, you can then avoid also the second creation of a temporary object (plus a copying) at each result by returning (from the * operator) by reference (this global object) instead of returning by value (a temporary copy).

This principle applied on your first example:
dim shared as UDT result
operator * (lhs as UDT, rhs as UDT) byref as UDT
dim as UDT result
result.data[0] = lhs.data[0] * rhs.data[0]
operator = result
end operator
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

Re: Overloading of operator.

Postby podvornyak » Sep 07, 2013 18:44

fxm wrote:byref as UDT

Thank you. Operator overloading is much clear for me now. One additional assignment per vertex - i can live with that.
fxm
Posts: 8959
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Overloading of operator.

Postby fxm » Sep 07, 2013 20:03

fxm wrote:Following this, from fbc version 0.90, you can then avoid also the second creation of a temporary object (plus a copying) at each result by returning (from the * operator) by reference (this global object) instead of returning by value (a temporary copy)

Otherwise, for fbc version < 0.90, another solution (for speed improvement) could be that the * operator returns an UDT ptr, but the code would be less readable:

Code: Select all

'.....

dim shared as UDT result
operator * (lhs as UDT, rhs as UDT) as UDT ptr
   result.data[0] = lhs.data[0] * rhs.data[0]
   operator = @result
end operator

dim as UDT udt1, udt2, udt3
udt1.data[0]=2
udt2.data[0]=4

udt3=*(udt1*udt2)
Gonzo
Posts: 722
Joined: Dec 11, 2005 22:46

Re: Overloading of operator.

Postby Gonzo » Sep 14, 2013 21:11

podvornyak wrote:
fxm wrote:... compatible ...

Than you for the tip. It is clear now - why... Anyway. I've changed my mind. Price of this "comfort coding" and "clean code" is too high - twice speed loss - from 300 fps to 150 in my case. :(


That sounds harsh, though you should never measure it in FPS to begin with
The rate could have gone from 0.001s to 0.002s which is 1ms extra.. Nothing too bad.
One of the issues have already been discussed - using byref's properly, and the other is getting inline insertions for the ultra short constructors and member functions.. this will probably be added in time.
And I think by the time it's added, you still won't have gone under 60fps if you code the program correctly :)

OpenGL is something that takes alot of time to get right, especially if you rely on matrices and vectors that are too generic
There are many matrix and vector operations that can be specialized for game programming

Especially translation and rotation of matrices
You can also batch transform and rotate at very high speeds, avoiding the overhead of function calls
You batch transform by defining a structure, lets say vertex_t
type vertex_t
as single x,y,z
as single u, v
as uinteger color
end type

then dim as mat4 myMatrix(1.0)
load in your 5000 vertices in vertex_t format, and batch transform:
myMatrix.batchTransform( @vertexData + offsetof(vertex_t, x) , sizeof(vertex_t) )

I'm guessing you are allocating the matrices because FB initializes variables, at least by default
That's unfortunate, because you REALLY want a 4x4 matrix on the stack
You also rarely need the lower row, essentially ending up with 4x3 or 3x4 matrix (i forget)
If you are intending to send the matrix to opengl, it will have to be 4x4

Usually scale matrices are initialized by constructor:
dim as mat4 myMatrix(scale)
dim as mat4 myMatrix(scalex, scaley, scalez)

This means that for identity matrix:
dim as mat4 myMatrix(1.0f)

Also, I would strongly advice you not to measure your class by the current abilities of the compiler,
and instead code it to be as easy to use as possible, instead focusing on implementing the backside of the matrix class in such a way that it is lightning fast. When the compiler starts optimizing OO better you will get an automatic benefit and you didn't have to do any extra work to get it.. :)
dodicat
Posts: 5757
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Overloading of operator.

Postby dodicat » Sep 15, 2013 0:41

The ways to 3D rotate are as many and varied as the days of Summer.
Here I've tried just a union with the all the gubbins held in the union array.
"You don't get me, I'm part of the Union" Strawbs
http://www.youtube.com/watch?v=69O8xmIeenU

Code: Select all

'--------------------------------------------------------------------
union V3 field =1
    As double a(1 to 4)
    Declare Function rotate(As V3,As V3,As V3) As V3
    Declare Function apply_perspective(As V3) As V3
    declare function distance(as V3) as double
End union
'---------------------------------------------------------------------
Function V3.rotate(c As V3,angle As V3,scale As V3=Type<V3>({1,1,1})) As V3
    Dim As double sx=Sin(angle.a(1)),sy=Sin(angle.a(2)),sz=Sin(angle.a(3))
    Dim As double cx=Cos(angle.a(1)),cy=Cos(angle.a(2)),cz=Cos(angle.a(3))
    Dim As double dx=this.a(1)-c.a(1),dy=this.a(2)-c.a(2),dz=this.a(3)-c.a(3)
    Return Type<V3>({(scale.a(1))*((cy*cz)*dx+(-cx*sz+sx*sy*cz)*dy+(sx*sz+cx*sy*cz)*dz)+c.a(1),_
    (scale.a(2))*((cy*sz)*dx+(cx*cz+sx*sy*sz)*dy+(-sx*cz+cx*sy*sz)*dz)+c.a(2),_
    (scale.a(3))*((-sy)*dx+(sx*cy)*dy+(cx*cy)*dz)+c.a(3),this.a(4)})
End Function
'-----------------------------------------------------------------------
Function V3.apply_perspective(eyepoint As V3) As V3
    Dim As double   w=1+(this.a(3)/eyepoint.a(3))
    Return Type<V3>({(this.a(1)-eyepoint.a(1))/w+eyepoint.a(1),(this.a(2)-eyepoint.a(2))/w+eyepoint.a(2),(this.a(3)-eyepoint.a(3))/w+eyepoint.a(3),this.a(4)})
End Function
'---------------------------------------------------------------------
function V3.distance(V2 as V3) as double
  Return Sqr((This.a(1)-v2.a(1))*(This.a(1)-v2.a(1))+(This.a(2)-v2.a(2))*(This.a(2)-v2.a(2))+(This.a(3)-v2.a(3))*(This.a(3)-v2.a(3)))   
end function
'------------------------------------------------------------------------
Sub QuickSort(array() As V3,begin As Integer,Finish As integer)
    Dim As Integer i=begin,j=finish
    Dim As V3 x =array(((I+J)\2))
    While  I <= J
        While array(I).a(3) > X.a(3):I+=1:Wend
            While array(J).a(3) < X.a(3):J-=1:Wend
                If I<=J Then Swap array(I),array(J): I+=1:J-=1
            Wend
            If J > begin Then QuickSort(array(),begin,J)
            If I < Finish Then QuickSort(array(),I,Finish)
        End Sub
 '------------------------------------------------------------------------       
        Function framecounter() As Integer
            Var t1=Timer,t2=t1
            Static As Double t3,frames,answer
            frames=frames+1
         If (t2-t3)>=1 Then t3=t2:answer=frames:frames=0
            Return answer
        End Function
  '=================================================================     

        #define map(a,b,x,c,d) ((d)-(c))*((x)-(a))\((b)-(a))+(c)
        'SET UP
        Dim As Integer num=4000
        Redim As V3 a(1 To num),r(1 To num)
        For n As Integer=1 To num
            With a(n)
        .a(1)=400+150*cos(n):.a(2)=300+150*sin(n): .a(3)=150*sin(1.2*n)
                var d=a(n).distance(Type<V3>({500,100,0}))
                .a(4)=Rgb(255-d/5,255-d/2,d/3)
            End With
        Next n
       
        Screenres 800,600,32
        color ,rgb(200,200,200)
        'centre of rotation and perspective eyepoint
        Dim As V3 ang,centre=Type<V3>({400,300,0}),eye=Type<V3>({400,300,500})
        Do
            ang=Type<V3>({ang.a(1)+.01,ang.a(2)+.005,ang.a(3)+.0025})
            For n As Integer=Lbound(a) To Ubound(a)
                r(n)=a(n).rotate(centre,ang,Type<V3>({1,1,1}))
                r(n)=r(n).apply_perspective(eye)
            Next n
            QuickSort(r(),Lbound(r),Ubound(r))
            Screenlock
            Cls
            For n As Integer=Lbound(r) To Ubound(r)
                var rad=map(-150,150,r(n).a(3),15,10)
                Circle(r(n).a(1),r(n).a(2)),rad,r(n).a(4),,,,f
            Next n
            Draw String(20,20),"FPS = " & framecounter,rgb(0,0,0)
            Screenunlock
            Sleep 1,1
        Loop Until Len(Inkey)
       
         

Return to “Beginners”

Who is online

Users browsing this forum: No registered users and 1 guest