A continuation of
this project I put in code snippets some time ago that has since become locked. If you posted something there before I had chance to reply: thanks. I had a break from coding. Resumed this a few weeks ago. Hopefully will be done in about a week.
A picture:
What is this?
It's 3D asteroids, but with a twist: instead of being in "flat" 3D space, it's on the surface of a "hypersphere" in 4 dimensions. This means is that it feels like 3D, but if you fly in a straight line, you come back to where you started.
Why did I do this?
For the technical challenge. The game isn't really intended to be much fun. Just a cool thing.
To do list as of 26th March:
Already existed in previous hypersphere project:
movement on hypersphere - effectively rotation in 4D.
Can see world - projection of hypersphere onto 3d space via simple DBP object positioning and scaling.
showing "axis" lines thru w=+/- 1
Done since:
Use of 2 quaternions to represent 4x4 rotation matrices - easy normalisation to stop cumulative errors
Random unit quaternion code - useful for random orientations
rotational and angular momentum for player
decal system - stars face camera, but do not rotate along line of sight axis relative to the world
use of central point light to get distance fogging (not just z distance)
code for interpolating quaternions (rotate by fraction of angle)
point lights in world - explosions, shots, etc. for small (relative to world) lights, using same scaling and positioning system as objects.
player can fire shots (single shot)
animated explosions
shot - asteroid collision. simple point in sphere.
simple blend mapping on asteroids
hud crosshairs
option to hide world axes
shot path/ asteroid polygon collision
cycle displayed world "axes" thru w,x,y,z=+/- 1
multiple explosions. explosion light assigned to brightest
multiple shots. shot light assigned to most recently fired
blendmapping + uv vertexdata system, allowing alpha with ghosted objects effect (so shots and explosions fade with distance)
asteroids move
doing collision checking (ungridded) for 140 asts ->~10000 checks. seems gridding not required.
billiard ball collisions between asteroids.
better calculation of explosion velocity when hits asteroid
impact explosions move away from asteroids a bit
more spherical asteroids to fit with simple collsion system
Stuff to do:
Make it into a fun game
Player collision detection with asteroids. maybe polygon.
make asteroids explode
tidy code, controls, optimise stuff blah blah blah
Possible to do (may skip):
exact calculation (trivial but fairly pointless) of explosion position
correct how light brightness scales with distance (just make a test prog - coloured fully lit object vs white object affected by light. what law does light follow?)
culling (so don't rotate, position etc stuff behind player)
make asteroids rotate
multiple explosion and shot lights. improve routine for deciding which explosions/shots to use lights for.
interpolation for double quaternions? may be trivial.
separate game engine iterations from screen update, using interpolation between "frames", allowing uncapped sync rate together with deterministic gameplay.
option to display hypercube, 120,600-cell centres etc.
tricks to improve speed and accuracy of polygon collision (unnecessary)
hypercube gridding for fast collision checking.
collisions between asteroids -polygon, with trading rotational intertia etc.
homing missiles.
Current code, as of 20th March:
(NB this is very messy! I only put it here because if I don't and my hard drive melts tonight, that will be extra annoying. I plan to make this tidier, better commented and give some explanatory documentation, should anyone wish to make any games with this wierd geometry! )
Rem Project: test polygon collision code
Rem Created: 20/03/2010 00:39:32
Rem ***** Main Source File *****
sync on
sync rate 0
load object "Rock01.x",1
load image "rocky.jpg",1
`ghost object on 1
texture object 1,1
obj_size#=object size(1)
cr#=obj_size#*3.0
make object sphere 2,obj_size#*0.1
do
camh#=camh#+mousemovey()
camr#=wrapvalue(camr#+mousemovex())
cx#=cr#*sin(camr#)
cz#=cr#*cos(camr#)
position camera cx#,camh#,cz#
point camera 0,0,0
numcalls=200
if mouseclick()
for n=1 to numcalls
`now do a collision thing, positioning sphere on surface of object.
`d#=intersect object(1, 0.0,0.0,0.0, cx#,camh#,cz#) `?!!! - goes to wierd place! perhaps needs to go from outside in
d#=intersect object(1, cx#,camh#,cz# ,0.0,0.0,0.0)
`hopefully that's fraction along line
`it's not. so also need to calc line length to normalise
len#=sqrt(cx#*cx#+camh#*camh#+cz#*cz#)
d#=d#/len#
d#=1.0-d# `because line goes from outside in
position object 2,d#*cx#,d#*camh#,d#*cz#
next n
endif
if spacekey() `what happens when intersect object can't give a # - answer : it gives ZERO!
position object 1,20,0,0
endif
text 0,0,str$(obj_size#)
text 0,10,str$(d#) `seems is abs dist along
text 100,0,str$(screen fps())
sync
loop
edit: wrong code! here's the main project
Rem Project: hypersphere thing
Rem Created: 24/03/2009 00:25:15
Rem ***** Main Source File *****
#constant blendmode 25
`prelim stuff
sync on:sync rate 50:autocam off
sync rate 0
set display mode 1280,720,32
position camera 0,0,0:set camera range 0.1,10000.0:point camera 1,0,0
`set camera fov 60
set camera fov 75
`set camera fov 140
set camera aspect 1.6666 `now got a 16:9 monitor..
set ambient light 50:point light 0,1,0,0:color light 0,rgb(128,128,128)
set normalization on
bgcol=0
`make sky instead???
`bgcol=rgb(150,190,200) `sky
bgcol=rgb(30,90,80)
fog on:fog color bgcol
`fog distance 70,110
`fog distance 100,250
fog distance 40,220
color backdrop bgcol
`try usng light instead of fog
set ambient light 0
color ambient light rgb(0,255,255)
point light 0,0,0,0
set light range 0,220 `seems to not do anything
set light range 0,1
color light 0,255,0,0 `test
`switch off light 0 `-apparently light 0 is rubbish!
color light 0,0
make light 1
set point light 1,0,0,0
set light range 1,250
color backdrop 0 `not sure how to make "light fogging" any colour other than black
`decrease standard light range so can have an extra light
color light 1,rgb(75,150,150)
`add in a light that I can drop at some postion. use a decal for it.
make light 2
`add in another light for explosion
make light 3
color light 3,0:set point light 3,0,0,0 `defaults not really required if am going to set them before 1st sync.
`color ambient light rgb(255,255,255) `<- not sure how to use light as fog. think untextured objects (coloured) have an
`effect like this.
fog off
set ambient light 0 `?!!
`using 4x4 to describe position and orientation.
`1st column - position on hypersphere
`next 3 columns - rotation.
`to get on 4 matrix relative to another, do M1T M2 - matrix 1 transposed x matrix 2
`um - i think!!
numboxes=200
dim mat4#(numboxes,3,3) `whole rotation and position.
`for points, only position (1st column) is required..
dim posw#(numboxes+100,3) `position in world - relative to camera..
dim mat4w#(numboxes,3,3) `relative to camera..
dim mat4t#(1,3,3) `temporary 4matrices for generating random rotations
dim mat4r#(3,3) `cold use an entry in above, but this makes code more readable.
`r stands for reflection
dim vector4#(3) `could use temp#(3) for this too, but this makes code more readable
dim temp#(3)
dim Euler#(3) `because can't pass DBP rotation matrix- have to use hellishly complicated
`formula to get euler angles, which DBP then internally converts back to your
`rotation matrix - extemely irritating!
dim quats(410,3) as float `quaternions
dim matrices(400,3,3) as float `matrices as used in functions from "quaternions test" project.
dim ObjectScale(1000) as float `can't find a DB command to get object scale. This seems pretty intuitive and useful,
`I could make more efficient workaround, but use this for now.
`pretty redundant, since have mat4 array, but just get it working first. make it efficient
`if can do that!
`build camera matrix
mat4#(0, 0, 0) = 1 : mat4#(0, 1, 0) = 0 : mat4#(0, 2, 0) = 0 : mat4#(0, 3, 0) = 0
mat4#(0, 0, 1) = 0 : mat4#(0, 1, 1) = 1 : mat4#(0, 2, 1) = 0 : mat4#(0, 3, 1) = 0
mat4#(0, 0, 2) = 0 : mat4#(0, 1, 2) = 0 : mat4#(0, 2, 2) = 1 : mat4#(0, 3, 2) = 0
mat4#(0, 0, 3) = 0 : mat4#(0, 1, 3) = 0 : mat4#(0, 2, 3) = 0 : mat4#(0, 3, 3) = 1
`make matrices for other points. will represent these points by spheres- since haven't
`got code to get world rotations yet..
`LOAD MODEL
mymesh=500
mymesh2=501
mymesh3=502
mymeshd1=503 `for decals
mymeshd2=504
mymeshd3=505
mymeshd4=506
mymesht=10
mymesht2=11
mymesht3=12
`load object "tessa_5pc.x",mymesh
load object "Rock01.x",mymesh
`load image "Marble_107_seamless_sample.jpg",mymesht
load image "RockyL.JPG",mymesht
set object radius mymesh,-1
texture object mymesh,mymesht
`set blend mapping on mymesh,1,mymesht,3,blendmode `try modes 5,6..
set blend mapping on mymesh,1,mymesht,3,25
load object "Rock01.x",mymesh2
load image "RockyL.JPG",mymesht2
set object radius mymesh2,-1
texture object mymesh2,mymesht2
set blend mapping on mymesh2,1,mymesht2,3,25
load object "Rock01.x",mymesh3
load image "sand_2.jpg",mymesht3
`load image "Rocky.JPG",mymesht3
REMSTART
load object "sub_rad1600.x",mymesh3
scale object mymesh3,1,1,1
make mesh from object mymesh3,mymesh3
delete object mymesh3
make object mymesh3,mymesh3,0
delete mesh mymesh3
REMEND
set object radius mymesh3,-1
texture object mymesh3,mymesht3
set blend mapping on mymesh3,1,mymesht3,3,25
`if spacekey()
`set blend mapping on
`load object "tessa1.x",mymesh
`scale object mymesh,1,1,1
`make mesh from object mymesh,mymesh
`delete object mymesh
`make object mymesh,mymesh,0
`delete mesh mymesh
`load object "sub_rad1600.x",mymesh `why obj not loading??
`load mesh "sub_rad1600.x",mymesh `BECAUSE HAD EXCLUDED .x conv in ini file!!!!
hide object mymesh
hide object mymesh2
hide object mymesh3
exclude object on mymesh
exclude object on mymesh2
exclude object on mymesh3
`now we have our points!!`
`now want some spheres to represent them in the world
`centre of island?
qislandpos=1
rand_quat_b(qislandpos)
qrotationL=2
qrotationR=3
totalqL=4
totalqR=5
qsmallmove=6
qtotalmoveL=7
qtotalmoveR=8
for n=1 to 30 `make an island??
instance object n,mymesh
`how to have random orientation, but clustered position???
`can i extract position, rotation parts from the L,R quaternions??
`first I want a pure random ROTATION quaternion pair!
`I think that's one where the 1,2,3 components are mirrored and the 0 component not..
`then apply movement quaternion (standard) plus random SMALL movement quaternion.
`can get total either by adding and normalising, or applying quats in sequence.
rand_quat_b(qrotationL)
quats(qrotationR,0)=quats(qrotationL,0) `MAKE CONJUGATE. COULD USE FUN FOR THIS.
quats(qrotationR,1)=-quats(qrotationL,1)
quats(qrotationR,2)=-quats(qrotationL,2)
quats(qrotationR,3)=-quats(qrotationL,3)
`now want to make a bigger ball!
`better to have code for random 3-vector, but this will make a cubey thing..
tot#=0.0
for c=1 to 3
quats(qsmallmove,c)=0.001*(rnd(200)-100)
inc tot#,quats(qsmallmove,c)*quats(qsmallmove,c)
next c
quats(qsmallmove,0)=sqrt(1.0-tot#*tot#)
_multiply_quaternions(qtotalmoveL,qsmallmove,qislandpos) `SMALL MOVE THEN BIG `nb rand rotation before, so doesn't really matter
_multiply_quaternions(qtotalmoveR,qislandpos,qsmallmove) `about having different L,R parts. (i think) - can just take as a pure movement.
`qtotalmoveL=qislandpos `no small move
`qtotalmoveR=qislandpos
_multiply_quaternions(totalqL,qrotationL,qtotalmoveL) `ROTATE THEN MOVE
_multiply_quaternions(totalqR,qtotalmoveR,qrotationR)
`^^ above works fine - makes a ball of randomly oriented thingys.
`maybe i have messed up and my quaternions are no longer unit length.
`are getting wierd stuff with conversion to euler
normalise_quat(totalqL)
normalise_quat(totalqR)
_convert_quats_to_4matrix(totalqL,totalqR,n)
`now are using different arrays, so copy across.
for a=0 to 3
for b=0 to 3
mat4#(n, a, b ) = matrices(n,a,b)
next b
next a
next n
for n=31 to numboxes-60
select rnd(1)
case 0
`make object sphere n,20,10,20
instance object n,mymesh2
endcase
case 1
`make object box n,20,4,4
instance object n,mymesh2
endcase
case 2
`make object cube n,10
instance object n,mymesh3
endcase
endselect
REMSTART
` color object n,rgb(100+rnd(155),100+rnd(155),100+rnd(155))
w=rnd(359)
` color object n,rgb(128+127*cos(w),128+127*cos(w+120),128+127*cos(w-120))
single_pixel_image(n,int(128+127*cos(w)),int(128+127*cos(w+120)),int(128+127*cos(w-120)),255)
texture object n,n
REMEND
`make_random_rotation_matrix(n) `this superceded by below. old func was fine, but new is more elegant and uses
`quaternions
rand_quat_b(1)
rand_quat_b(2)
_convert_quats_to_4matrix(1,2,n)
`now are using different arrays, so copy across.
for a=0 to 3
for b=0 to 3
mat4#(n, a, b ) = matrices(n,a,b)
next b
next a
next n
`load image "3334.jpg",1
`for n=1 to numboxes-60
`texture object n,1 `OVERRIDE!
`next n
`make some decal objects!!
`hopefully euler rotation will work out nicely.
`cam direction is x.
`so could work! rotate about z, then about y(up), then about x.
`with decals, rotation - ie full 4x4 rotation matrix, has no sense
`single quaternion sufficient to tell position.
`how to implement? could adapt full random 4matrix position/rotation
`then just keep track of rolling to stop decals spinning.
`may be more efficient way - like just keeping move quaternion.
`load image "a2.jpg",numboxes+1
white_light_tex=20
load image "ls1-256.jpg",white_light_tex
n=mymeshd4
make object plain n,10,10:yrotate object n,180:fix object pivot n
texture object n,white_light_tex
ghost object on n
disable object zwrite n
hide object n
exclude object on n
set object light n,0 `make fully lit
for n=numboxes+1 to numboxes+20
rand_quat_b(n) `movement quaternion
`make object cube n,10
`make object plain n,20,20:yrotate object n,180:fix object pivot n
`texture object n,white_light_tex
`ghost object on n
`disable object zwrite n
instance object n,mymeshd4
next n
dim remember_spin#(numboxes+100) `for decals
`inefficient but don't know which ones are using!
for n=0 to 400
_init_quaternion(n,1.0,0.0,0.0,0.0)
next n
`initialisation of quats messed up our decals!!
for n=numboxes+1 to numboxes+20
rand_quat_b(n) `movement quaternion
next n
red_light_tex=21
green_light_tex=22
blue_light_tex=23
load image "red_star.jpg",red_light_tex `numboxes-1
load image "green_star.jpg",green_light_tex `numboxes-2
load image "blue_star.jpg",blue_light_tex `numboxes
`make a line of boxes..
`use decals inastead.
n=mymeshd1
make object plain n,10,10:yrotate object n,180:fix object pivot n
texture object n,blue_light_tex
ghost object on n
disable object zwrite n
hide object n
exclude object on n
set object light n,0 `make fully lit
n=mymeshd2
make object plain n,10,10:yrotate object n,180:fix object pivot n
texture object n,red_light_tex
ghost object on n
disable object zwrite n
hide object n
exclude object on n
set object light n,0 `make fully lit
n=mymeshd3
make object plain n,10,10:yrotate object n,180:fix object pivot n
texture object n,green_light_tex
ghost object on n
disable object zwrite n
hide object n
exclude object on n
set object light n,0 `make fully lit
`make a line of boxes..
for n=numboxes-59 to numboxes-40
remstart
make object plain n,10,10:yrotate object n,180:fix object pivot n
texture object n,green_light_tex
ghost object on n:disable object zwrite n
remend
instance object n,mymeshd3
moveup#=360.0*( (n+0.5) / 20.0)
c#=cos(moveup#)
s#=sin(moveup#)
quats(n,0)=c#
quats(n,1)=0.0
quats(n,2)=s#
quats(n,3)=0.0
next n
for n=numboxes-39 to numboxes-20
remstart
make object plain n,10,10:yrotate object n,180:fix object pivot n
texture object n,red_light_tex
ghost object on n:disable object zwrite n
remend
instance object n,mymeshd2
movefwd#=360.0*( (n+0.5) / 20.0)
c#=cos(movefwd#)
s#=sin(movefwd#)
quats(n,0)=c#
quats(n,1)=s#
quats(n,2)=0.0
quats(n,3)=0.0
next n
for n=numboxes-19 to numboxes
remstart
make object plain n,10,10:yrotate object n,180:fix object pivot n
texture object n,blue_light_tex
ghost object on n:disable object zwrite n
remend
instance object n,mymeshd1
` make object box n,5,5,20
` make object sphere n,5,5,7
` single_pixel_image(n,100,100,255,255)
` texture object n,n
` for a=0 to 3:for b=0 to 3
` mat4#(n, a, b)=mat4#(0, a, b)
` next b:next a
moveleft#=360.0*( (n+0.5) / 20.0)
c#=cos(moveleft#)
s#=sin(moveleft#)
` for t=0 to 3
` temp#(t)=mat4#(n, 0, t)
` mat4#(n, 0, t) = mat4#(n, 0, t) * c# + mat4#(n, 3, t) * s#
` mat4#(n, 3, t)= mat4#(n, 3, t) * c# - temp#(t) * s#
` next t
quats(n,0)=c#
quats(n,1)=0.0
quats(n,2)=0.0
quats(n,3)=s#
next n
`texture object numboxes+1,blue_light_tex `make drop light blue `WORKS ONLY WHEN NOT INSTANCED!
delete object numboxes+1
instance object numboxes+1,mymeshd1
delete object numboxes+2
instance object numboxes+2,mymeshd2 `red
global player_qL
global player_qR
player_qL=100 `player's quaternion!
player_qR=101
_init_quaternion(player_qL,1.0,0.0,0.0,0.0)
_init_quaternion(player_qR,1.0,0.0,0.0,0.0)
expl_im=1000 `should make lower later!!!
load image "explosion12.png",expl_im
expl_test_obj=1000
make object plain expl_test_obj,10,10:yrotate object expl_test_obj,180:fix object pivot expl_test_obj
`move closer to cam?
offset limb expl_test_obj,0,0,0,1
`position object expl_test_obj,0,0,50
`lock object on expl_test_obj
texture object expl_test_obj,expl_im
`set alpha mapping on expl_test_obj,100
ghost object on expl_test_obj:disable object zwrite expl_test_obj:set object light expl_test_obj,0
expl_x=0
expl_y=0
expl_texnum=0 `8x8=64 textures
scale object texture expl_test_obj,0.125,0.125 `1/8th
xhairs_objnum=1001
o=xhairs_objnum
make object plain o,15,10
position object o,0,0,80
lock object on o
set object light o,0
ghost object on o
disable object zwrite o
disable object zread o
`disable object zdepth??
load image "xhairs.jpg",o
texture object o,o
GLOBAL DISPLAYINFO `press 2/1 to switch on/off
do
IF DISPLAYINFO
text 400,0,str$(expl_texnum)
ENDIF
expl_texnum= (expl_texnum+keystate(49)-keystate(48)) &&63 `n,b keys
expl_x_last=expl_x
expl_y_last=expl_y
expl_x=expl_texnum&&7
expl_y=expl_texnum/8
IF DISPLAYINFO
text 400,10,str$(expl_x)
text 400,20,str$(expl_y)
ENDIF
scroll object texture expl_test_obj,0.125*(expl_x-expl_x_last),0.125*(expl_y-expl_y_last)
`text 0,0,str$(screen fps())
`370 fps
`rotate camera and move it! - "rotation" about 4x3 / 2 = 6 possible axes- movement along 3 axes,
`and rotation about 3. rotation of one column into another..
camera_movement()
`display the "points"
`think i want to do column 0 of camera matrix, "dotted" with the point position 4vector.
`NB awesome thing about rotation matrices (orthogonal, determinant 1..)
`- inverse is the same as transpose.. SWEET!
for n=1 to numboxes-60 `now using decals for some of axes
for a=0 to 3:for b=0 to 3
sum#=0.0
for c=0 to 3
inc sum#,mat4#(n,a,c)*mat4#(0,b,c)
next c
mat4w#(n,a,b)=sum#
next b:next a
`position it - using matrix row or column 0 (not sure which) for position..
for c=0 to 3 `cam matrix column = 0 to 3
posw#(n, c) = mat4w#(n, 0 ,c) `COULD JUST USE MAT IN BELOW CODE-
next c `NO ACTUAL NEED FOR POSW ARRAY
next n
`now position sphere in the world..
`DIRECTION is given by x,y,z (1,2,3) of posw. distance related to w (0)
`hope we have right formula for distance. seems a little complicated..
for n=1 to numboxes-60 `now some axis objects are decals
a#=1.0 + posw#(n, 0)
`distance "culling" - to stop stuff on opposite "side" getting all huge and visible!
` if a#<0.8 then hide object n else show object n
if a#<0.15 then hide object n else show object n
dist#=100.0/a#
position object n, dist#*posw#(n, 1) , dist#*posw#(n, 2) , dist#*posw#(n, 3)
scale object n, dist#,dist#,dist#
ObjectScale(n)=dist# `useful thing to have- did this so can easily put explosion to same scale as shot object.
`might have been easier to just use one of the stars as explosion (am currently doing this anyway!)
`next n
`for n=1 to numboxes `a separate loop over n
ct#=posw#(n, 0)
st#=sqrt(1.0-ct#*ct#)
ctm#=ct#-1.0
p#=posw#(n, 1)/st#
q#=posw#(n, 2)/st#
r#=posw#(n, 3)/st#
`now build matrix - first row and column should be the same as already calculated -
`do not require calculation, but do so anyway for now just to check this works..
s=0 `use a spare matrix - number doesn't matter - maybe could just use mat4t#()
REMSTART
mat4t#(s,0,0)=ct# :mat4t#(s,1,0)=0.0-p#*st# :mat4t#(s,2,0)=0.0-q#*st# :mat4t#(s,3,0)=0.0-r#*st#
mat4t#(s,0,1)=p#*st# :mat4t#(s,1,1)=1.0+p#*p#*ctm# :mat4t#(s,2,1)=p#*q#*ctm# :mat4t#(s,3,1)=p#*r#*ctm#
mat4t#(s,0,2)=q#*st# :mat4t#(s,1,2)=p#*q#*ctm# :mat4t#(s,2,2)=1.0+q#*q#*ctm# :mat4t#(s,3,2)=q#*r#*ctm#
mat4t#(s,0,3)=r#*st# :mat4t#(s,1,3)=p#*r#*ctm# :mat4t#(s,2,3)=q#*r#*ctm# :mat4t#(s,3,3)=1.0+r#*r#*ctm#
REMEND
`OPTIMISED VERSION:
`pst#=p#*st#:qst#=q#*st#:rst#=r#*st#
pctm#=p#*ctm#:qctm#=q#*ctm#:rctm#=r#*ctm#
mat4t#(s,0,0)=ct# :mat4t#(s,1,0)=0.0-posw#(n, 1) :mat4t#(s,2,0)=0.0-posw#(n,2) :mat4t#(s,3,0)=0.0-posw#(n, 3)
mat4t#(s,0,1)=posw#(n,1) :mat4t#(s,1,1)=1.0+p#*pctm# :mat4t#(s,2,1)=p#*qctm# :mat4t#(s,3,1)=p#*rctm#
mat4t#(s,0,2)=posw#(n,2) :mat4t#(s,1,2)=p#*qctm# :mat4t#(s,2,2)=1.0+q#*qctm# :mat4t#(s,3,2)=q#*rctm#
mat4t#(s,0,3)=posw#(n,3) :mat4t#(s,1,3)=p#*rctm# :mat4t#(s,2,3)=q#*rctm# :mat4t#(s,3,3)=1.0+r#*rctm#
`guess at rows/columns to use..
t=1 `use another spare matrix - number doesn't matter - maybe could just use mat4t#()
for a=0 to 3
for b=0 to 3
sum#=0.0
for u=0 to 3
inc sum#, mat4t#(s,a,u) * mat4w#(n,b,u) `<< this gets something that looks kind of right..
next u
mat4t#(t,a,b)=sum#
next b
next a
`convert matrix (lower right 3x3 matrix inside this 4x4 matrix)
`to euler angles. the following code by Diggsey i might be able to gonvert to something that works..
REMSTART
done=0
`SUBBED IN fw=2:ri=3:up=1:x=3:y=1:z=2
if mat4t#(t, 3, 1) > 0.99999
text 0,0,"******"
text object screen x(n),object screen y(n),"HERE B"
Euler#(2) = atanfull(0.0-mat4t#(t, 2, 3),mat4t#(t, 2, 2))
Euler#(3) = -90.0
Euler#(1) = 0.0
done=1
endif
if mat4t#(t, 3, 1) < -0.99999
text 0,0,"#######"
text object screen x(n),object screen y(n),"HERE A editing"
Euler#(2) = atanfull(0.0-mat4t#(t, 2, 3),mat4t#(t, 2, 2))
`Euler#(2) = atanfull(mat4t#(t, 2, 2),0.0-mat4t#(t, 2, 3))
Euler#(3) = 90.0
Euler#(1) = 0.0
done=1
endif
if done=0
REMEND
Euler#(1) = atanfull(mat4t#(t, 2, 1),mat4t#(t, 1, 1))
Euler#(2) = atanfull(mat4t#(t, 3, 2),mat4t#(t, 3, 3))
```if controlkey()
`Euler#(3) = asin(0.0-mat4t#(t, 3, 1))
```else
`^^ above seems numerically unstable near poles. better solution - try below..
`NB WITH NEW CODE, OTHER THINGS (if>0.99, if<-0.99) ABOVE MAY BE REDUNDANT!
temp#=sqrt(mat4t#(t, 3, 2)*mat4t#(t, 3, 2) + mat4t#(t, 3, 3)*mat4t#(t, 3, 3) )
Euler#(3) = atanfull(-mat4t#(t, 3, 1),temp#)
```endif
` endif
rotate object n, Euler#(2),Euler#(3),Euler#(1)
next n
`length of rotation quaternion parts 1,2,3
rqlen#=sqrt (1.0-quats(rotquatL,0)*quats(rotquatL,0))
`SIMILAR THING FOR DECALS
`NB haven't looked at skipping conversion to 4matrix. Can i go straight from L,R quats to 3matrix?
`for n=numboxes+1 to numboxes+20
if displayaxes:startfrom=numboxes-59:else:startfrom=numboxes+1:endif
for n=startfrom to numboxes+20 `now decals for some axis
` movequat=3 `L,R the same `PLAYER MOVEMENT QUATERNION.
`may want to use conjugate.
for b=0 to 3
sum#=0.0
for c=0 to 3
`inc sum#,mat4#(n,0,c)*mat4#(0,b,c)
inc sum#,quats(n,c)*mat4#(0,b,c)
next c
posw#(n, b)=sum#
next b
`next n
`for n=1 to numboxes
a#=1.0 + posw#(n, 0)
`distance "culling" - to stop stuff on opposite "side" getting all huge and visible!
` if a#<0.8 then hide object n else show object n
if a#<0.15 then hide object n else show object n
dist#=100.0/a#
position object n, dist#*posw#(n, 1) , dist#*posw#(n, 2) , dist#*posw#(n, 3)
scale object n, dist#,dist#,dist#
ObjectScale(n)=dist# `useful thing to have- did this so can easily put explosion to same scale as shot object.
`might have been easier to just use one of the stars as explosion (am currently doing this anyway!)
`one of them is a point light source
if n=numboxes+1
position light 2,object position x(n),object position y(n),object position z(n)
set light range 2,dist# `want some scale factor!
`lightcolor=int(255000.0/dist#) `guess a function- should think about what it should be later.
if posw#(n, 0)>0.0
lightcolor=int(posw#(n, 0) *255.0)
else
lightcolor=0
endif
color light 2,rgb(0,0,lightcolor) `should make dimmer as gets more distant too.
endif
`orientation? want to be pointed at camera.
`this is a bit fudgey! works for looking around (at least for central decals)
`doesn't work when roll camera!
`NEED TO SORT THIS OUT
set object rotation zyx n
rs#=atanfull(posw#(n,2),-posw#(n,3))
`z#=wrapvalue(object angle z(n) + (remember_spin#(n)-rs#) )
` z#=wrapvalue( (object angle z(n) -rs#)*(posw#(n,1)/sqrt(1.0-posw#(n,0)*posw#(n,0)))+remember_spin#(n) )
`try override: -works the same at the mo.
`z#=-rs#
` remember_spin#(n)=rs#
`should add effect of camera rotation..
`guess
dista#=sqrt(1.0-posw#(n,0)*posw#(n,0))
sum#=0.0
rotquatL=1
remstart
for c=1 to 3
inc sum#,quats(rotquatL,c)*posw#(n,c)
`WANT IN CAMERA FRAME,
next c
ANG#=2.0*ASIN(sum#/dista#)
remend
````*****************
REMSTART
`1st get angle of cam rotation
ANG1#=2.0*Acos(quats(rotquatL,0)) `ONLY WORKS IN 1 DIRECTION :(
`now need to have something to do with angle between rotation axis (rot quat real part, normalised)
`and world position (normalised)
normfactor#=sqrt( ( 1.0-quats(rotquatL,0)*quats(rotquatL,0) ) * ( 1.0- posw#(n,0)*posw#(n,0) ) )
for c=1 to 3
inc sum#,quats(rotquatL,c)*posw#(n,c)
next c
sum#=sum#/normfactor#
`need something that keeps sum at +/- 1, but increases it for smaller values. try..
`sum#=(1.0/45.0)*atan(sum#)
`sum#=sin(sum#*90.0)
`sum#=sum#-sin(sum#*360.0)
`sum#=sum#*sin(sum#*90.0)*sin(sum#*90.0)
`ang#=ang1#*(1.0-sqrt(1.0-sum#*sum#))*(sum#/abs(sum#))
`ANG#=2.0*Acos(quats(rotquatL,0)*sum#) `ONLY WORKS IN 1 DIRECTION :(
if shiftkey()=0
`inc remember_spin#(n),ang1# `*sum#
endif
`^^ doesn't work.
ang1#=2.0*Acos(quats(rotquatL,0)) `sort directionality later
`dotb#=(quats(rotquatL,1))/sqrt( 1.0- quats(rotquatL,0)*quats(rotquatL,0) ) `guess - works for pure roll.
dotb#=(quats(rotquatL,1))/sqrt( 1.0- quats(rotquatL,0)*quats(rotquatL,0) ) `guess - works for pure roll.
ang2#=ang1#*dotb#
angt#=ang2#
`inc angt#,ang1#* ( quats(rotquatL,2)*posw#(n,2) + quats(rotquatL,3)*posw#(n,3) ) / sqrt( 1.0- quats(rotquatL,0)*quats(rotquatL,0)) `guess
`inc angt#,ang1#*((quats(rotquatL,2)*posw#(n,2) +quats(rotquatL,3)*posw#(n,3)) / sqrt( 1.0- quats(rotquatL,0)*quats(rotquatL,0))) * (1.0-dotb#*dotb#) `guess
ang3#=1.0+Acos(posw#(n,1)/dotb#)
`if shiftkey()=0 then inc angt#,ang1#*(ang3#/180.0) * ((quats(rotquatL,2)*posw#(n,2) +quats(rotquatL,3)*posw#(n,3)) / sqrt( 1.0- quats(rotquatL,0)*quats(rotquatL,0)))
`if shiftkey()=0 then inc angt#,ang1#* ((quats(rotquatL,2)*posw#(n,2) +quats(rotquatL,3)*posw#(n,3)) / sqrt( (1.0- quats(rotquatL,0)*quats(rotquatL,0)) * (1.0- posw#(n,0)*posw#(n,0)) ))
`if shiftkey()=0 then inc angt#,ang1#*(acos(dotb#)/180.0)
dotc#=((quats(rotquatL,2)*posw#(n,2) +quats(rotquatL,3)*posw#(n,3)) / sqrt( 1.0- quats(rotquatL,0)*quats(rotquatL,0)))
inc remember_spin#(n),angt#
rotate object n,rs#,90.0+acos(posw#(n,1)/dista#),-rs# ` +remember_spin#(n)
`rotate object n,remember_spin#(n),90.0+acos(posw#(n,1)/sqrt(1.0-posw#(n,0)*posw#(n,0))),0.0
REMEND
`this works (sort of) for keeping things from rolling in camera frame
if dista#>0.001 `prevent 0 distance problems!! - maybe should just cull stuff by z dist.
frontness#=posw#(n,1)/dista#
else
frontness#=0.0
text 50,50,"testA"
endif
`inc remember_spin#(n), (rs#-object angle x(n)) * frontness#
ta#=wrapvalue(rs#-object angle x(n)+180.0)-180.0 `change from 0-360 to -180 to +180
rs2#=wrapvalue( -object angle z(n) + (ta#) * frontness#)
`rs2#=-remember_spin#(n)+ (ta#) * frontness#
ac#=0.0:if frontness#<1.0 then ac#=acos(frontness#) `to cure bug with looking straight at stuff
rotate object n,rs#,90.0+ac#,-rs2#
remember_spin#(n)=object angle z(n)
`remember_spin#(n)=object angle z(n)
`add in roll we want.
sum#=0.0
for c=1 to 3
inc sum#,quats(rotquatL,c)*posw#(n,c)
next c
denom#=rqlen#*dista#
if denom#>0.000001 `same 0 lenght dista thingy
sum#=sum#/denom#
else
``` text 50,60,"testB"
` sum#=0.0 `not sure what sense this has, but should stop z angle going undefined.
endif
ANG1#=2.0*Acos(quats(rotquatL,0)) `ONLY WORKS IN 1 DIRECTION :(
`if spacekey() then
zrotate object n,object angle z(n)+ang1#*sum#
`^^WORKS!!!!!
`zrotate object n,0 `debug `problem persists with this.
`xrotate object n,0 `debug `problem persists
`yrotate object n,90 `fixes problem
`if n=numboxes+1 `see that problem can be that angle z is undefined
` text 20,20,str$(object angle x(n))
` text 20,30,str$(object angle y(n))
` text 20,40,str$(object angle z(n))
`endif
next n
`allow view movement
viewturn#=0.9*viewturn#+0.1*(keystate(30)-keystate(32) +keystate(31)*2) `last is look back
point camera cos(90.0*viewturn#),0,sin(90.0*viewturn#)
`turn camera right viewturn#
`quick and messy x-hairs
hide mouse
ink rgb(255,255,255),0
`dot screen width()/2,screen height()/2 `NOW USING
`circle screen width()/2,screen height()/2,7 `OBJECT CROSSHAIRS
text 0,0,str$(screen fps())
`should put this elsewhere.
`allow dropping of a decal to player position
`put light 2 here.
`make size of light 2 proportional to scale of stuff at it's location.
`also scale it's brightness in some way (drop off with distance)
velquat=401
`copy old player position to something, so can divide to get velocity.
`don't think using quat 6 yet
player_q_old=6
_copy_quaternion(0,player_q_old)
`conjugate quat?
`quats(player_q_old,0)=-quats(player_q_old,0)
`get player position quaternion. should be getting this anyway. expect useful.
_init_quaternion(0,mat4#(0,0,0),mat4#(0,0,1),mat4#(0,0,2),mat4#(0,0,3))
m= numboxes+1
REMSTART
if keystate(16) `q `DROP LIGHT!
_copy_quaternion(0,m)
`quats(m,c)=quats(0,c) `equiv to above (c=0 to 3)
`take difference in player positions in consecutive frames, to set velocity of dropped light.
`may need some conjugate / inverse quats here.
` quats(player_q_old,0)=-quats(player_q_old,0) `conjugate quat?
for c=1 to 3
quats(player_q_old,c)=-quats(player_q_old,c) `conjugate quat? `seems complicated!
next c `maybe want a "divide quat" function..
_multiply_quaternions(velquat,0,player_q_old) `get shooting velocity quat.
endif
REMEND
`diagnostic - display this "velocity" to screen.
`want to see if is an easier way to get it from player "velocity" movequat.
`want also to be able to add front velocity or whatever for shooing instead of dropping.
`DO THE ABOVE ALWAYS (for diagnostic.)
for c=1 to 3
quats(player_q_old,c)=-quats(player_q_old,c) `conjugate quat? `seems complicated!
next c
_multiply_quaternions(402,0,player_q_old) `get shooting velocity quat.
if keystate(16) `q `DROP LIGHT!
_copy_quaternion(0,m)
_multiply_quaternions(velquat,0,player_q_old) `get shooting velocity quat.
shot_active=1
endif
if keystate(2)
displayinfo=1
endif
if keystate (3)
displayinfo=0
endif
`V. simple code to hide axes.
`skip positioning of these when off
if keystate(5)
displayaxes=1
for n=numboxes-59 to numboxes
show object n
exclude object off n
next n
endif
if keystate(4)
displayaxes=0
for n=numboxes-59 to numboxes
hide object n
exclude object on n
next n
endif
IF DISPLAYINFO
`display quat 402
for c=0 to 3
text 100,10*c,str$(quats(402,c),7)
ink rgb(250,0,0),0
text 100+400*quats(402,c),205+20*c,"|" `test bars
ink rgb(255,255,255),0
next c
ENDIF
`difference between quat 402 and testquat
testquat=410
IF DISPLAYINFO
for c=0 to 3
text 200,300+10*c,str$(quats(testquat,c)-quats(402,c),7)
next c
ENDIF
if gundelay>0
dec gundelay
else
if keystate(17) `w- drop light using velocity quaternion calculated elsewhere- where will be simpler to add front velocity.
_copy_quaternion(0,m)
shootquatw=407
_copy_quaternion(shootquatw,velquat) `from,to
gundelay=30
shot_active=1
endif
endif
_multiply_quaternions(m,velquat,m) `apply velocity
`now do a collision check with asteroids.
`simple point in sphere.
collide=0
for n=1 to numboxes-60
`mat4#(n,a,c) `0th row or column is position i think
sum#=0.0
for c=0 to 3
d#=mat4#(n,0,c)-quats(m,c) `m is the shot
inc sum#,d#*d#
next c
if sum#<0.02
collide=1
endif
`alternate code could be q(ast).q(shot)*, then check whether less than 1-radsq, or something.
`quat mult = 16 mults, adding 16 #s together
`summing squares of differences is taking 4 differences, doing 4 squares, and addin 4 numbers together.
`-> better i guess!
next n
`if keystate(19) `r=reset
`collide=0
`endif
`text 500,0,str$(collide)
e=numboxes+2
`put explosion to position
if collide and shot_active
_copy_quaternion(m,e)
` collide=0 `take care of this earlier now- here resulted (with shot active if) in explosion upon firing
`stop shot (should deactivate it, but this will work too)
_init_quaternion(velquat,1.0,0.0,0.0,0.0)
expl_texnum=0
shot_active=0
endif
set object rotation zyx expl_test_obj `should put this to start of program?
`set object to object orientation expl_test_obj,e
position object expl_test_obj, object position x(e),object position y(e),object position z(e)
rotate object expl_test_obj, object angle x(e),object angle y(e),object angle z(e) `-180.0
`sc#=1000.0*limb scale x(e,0) `doesn't work
`scale object expl_test_obj,sc#,sc#,sc#
scale object expl_test_obj,ObjectScale(e),ObjectScale(e),ObjectScale(e)
`rotate object expl_test_obj, object angle x(e),object angle y(e)-180.0,object angle z(e) `need this if don't rotate by 180 y and fix object pivot
`set object cull expl_test_obj,0
if expl_texnum<62 `means never use tex 0. also, explosion gets played at start of game.
inc expl_texnum
endif
position light 3,object position x(e),object position y(e),object position z(e)
`0.0622 = 255/4096 ~1/16
expbright=(1024-(expl_texnum-31.5)^2.0)/4
`simple temp dist brightness-
`assume is same place as light 2 (won't be if fire again when explosion on)
`also rounding error bigger than required.
`expbright=expbright*(lightcolor/256.0)
expbright=expbright*((lightcolor+100)/356.0) `just a fudge to get more range
color light 3,rgb(expbright,0,0)
set light range 3,4.0*ObjectScale(e)
``````player_q_old=6
``````_copy_quaternion(0,player_q_old)
REMSTART
`TEST - see if we can find a way to get player frame and world frame
`velocities that are constant!! - is there a way? should stay constant
`if both player frame vel, and player not rotating.
movequat=3 `think elsewhere in a function
_copy_quaternion(movequat,velquat)
`guess at making into a world velocity??
`if spacekey()<10
_multiply_quaternions(velquat,player_qR,velquat) `maybe want to use inverse? `FAIL FAIL FAIL
`_multiply_quaternions(velquat,velquat,player_qL) `THIS IS EFFED UP THINK ABOUT IT WHEN AWAKE
`what is invariant? something so can get invariant velocity in world frame
`when player travelling forwards
for c=0 to 3
text 100,80+10*c,str$(quats(movequat,c),5)
text 200,80+10*c,str$(quats(velquat,c),5)
next c
REMEND
sync
loop
end
function camera_movement()
`build camera matrix
`mat4#(0, 0, 0) = 1 : mat4#(0, 1, 0) = 0 : mat4#(0, 2, 0) = 0 : mat4#(0, 3, 0) = 0
`mat4#(0, 0, 1) = 0 : mat4#(0, 1, 1) = 1 : mat4#(0, 2, 1) = 0 : mat4#(0, 3, 1) = 0
`mat4#(0, 0, 2) = 0 : mat4#(0, 1, 2) = 0 : mat4#(0, 2, 2) = 1 : mat4#(0, 3, 2) = 0
`mat4#(0, 0, 3) = 0 : mat4#(0, 1, 3) = 0 : mat4#(0, 2, 3) = 0 : mat4#(0, 3, 3) = 1
movefwd#=( (mouseclick()&&1) - ((mouseclick()&&2)>>1) )*0.5 ` - mouseclick()&&2
pitch#=(mousemovey())*-0.1
turn#=(mousemovex())*-0.1
moveup#=(upkey()-downkey())*0.1 `1.0
moveleft#=(leftkey()-rightkey())*0.1
roll#=keystate(51)-keystate(52)
REMSTART
`movefwd#=(shiftkey()-controlkey())*-0.5
movefwd#=( (mouseclick()&&1) - ((mouseclick()&&2)>>1) )*0.5 ` - mouseclick()&&2
`movefwd#=0.0-5.0*moveup# `override- see what happens to matrix when move along diagonal
c#=cos(movefwd#)
s#=sin(movefwd#)
for t=0 to 3
temp#(t)=mat4#(0, 0, t)
mat4#(0, 0, t) = mat4#(0, 0, t) * c# + mat4#(0, 1, t) * s#
mat4#(0, 1, t)= mat4#(0, 1, t) * c# - temp#(t) * s#
next t
`pitch#=(upkey()-downkey())*2.0
pitch#=(mousemovey())*-0.1
c#=cos(pitch#)
s#=sin(pitch#)
for t=0 to 3
temp#(t)=mat4#(0, 1, t)
mat4#(0, 1, t) = mat4#(0, 1, t) * c# + mat4#(0, 2, t) * s#
mat4#(0, 2, t)= mat4#(0, 2, t) * c# - temp#(t) * s#
next t
`turn#=(leftkey()-rightkey())*2.0
turn#=(mousemovex())*-0.1
c#=cos(turn#)
s#=sin(turn#)
for t=0 to 3
temp#(t)=mat4#(0, 1, t)
mat4#(0, 1, t) = mat4#(0, 1, t) * c# + mat4#(0, 3, t) * s#
mat4#(0, 3, t)= mat4#(0, 3, t) * c# - temp#(t) * s#
next t
moveup#=(upkey()-downkey())*0.1 `1.0
c#=cos(moveup#)
s#=sin(moveup#)
for t=0 to 3
temp#(t)=mat4#(0, 0, t)
mat4#(0, 0, t) = mat4#(0, 0, t) * c# + mat4#(0, 2, t) * s#
mat4#(0, 2, t)= mat4#(0, 2, t) * c# - temp#(t) * s#
next t
moveleft#=(leftkey()-rightkey())*0.1
`moveleft#=2.0*moveup# `override- see what happens to matrix when move along diagonal
c#=cos(moveleft#)
s#=sin(moveleft#)
for t=0 to 3
temp#(t)=mat4#(0, 0, t)
mat4#(0, 0, t) = mat4#(0, 0, t) * c# + mat4#(0, 3, t) * s#
mat4#(0, 3, t)= mat4#(0, 3, t) * c# - temp#(t) * s#
next t
roll#=keystate(51)-keystate(52)
c#=cos(roll#)
s#=sin(roll#)
for t=0 to 3
temp#(t)=mat4#(0, 2, t)
mat4#(0, 2, t) = mat4#(0, 2, t) * c# + mat4#(0, 3, t) * s#
mat4#(0, 3, t)= mat4#(0, 3, t) * c# - temp#(t) * s#
next t
REMEND
`guess new code to do rotation and movement via quaternions.
`later will want to keep track of momentum etc - meaning want world frame. cross this bridge later.
myconst#=(3.14/180.0)
`movetot#=sqrt ( 1.0 - myconst#*myconst#*(movefwd#*movefwd# + moveleft#*moveleft# +moveup#*moveup#) ) `should use sines, but small angle approx?
`rottot#=sqrt ( 1.0 - myconst#*myconst#*(roll#*roll# + turn#*turn# +pitch#*pitch#) )
rotquatL=1
rotquatR=2
movequat=3 `L,R the same
`quats(rotquatL,0)=rottot#
`SMALL ANGLE APPROX- ADD SMALL PARTS OF QUATS INSTEAD OF MULTIPLYING WHOLE LOT.
quats(rotquatL,1)=0.99*quats(rotquatL,1)-0.02*myconst#*roll# `this is sin(roll)
quats(rotquatL,2)=0.99*quats(rotquatL,2)+0.02*myconst#*turn#
quats(rotquatL,3)=0.99*quats(rotquatL,3)-0.02*myconst#*pitch#
tot#=0.0
for c=1 to 3
inc tot#,quats(rotquatL,c)*quats(rotquatL,c)
next c
quats(rotquatL,0)=sqrt(1.0-tot#)
`quats(movequat,0)=movetot#
braking#=0.975-0.05*controlkey()
quats(movequat,1)=braking#*quats(movequat,1)-0.03*myconst#*movefwd#
quats(movequat,2)=braking#*quats(movequat,2)-0.02*myconst#*moveup#
quats(movequat,3)=braking#*quats(movequat,3)-0.02*myconst#*moveleft#
tot#=0.0
for c=1 to 3
inc tot#,quats(movequat,c)*quats(movequat,c)
next c
quats(movequat,0)=sqrt(1.0-tot#)
IF DISPLAYINFO
`display movequat. is it the same as velocity got other method? same 0th component?
for c=0 to 3
text 200,10*c,str$(quats(movequat,c),7)
next c
ENDIF
`makes sense - square quaternion - zeroth component (small angles) 4x further away from 0.
testquat=410
_multiply_quaternions(testquat,movequat,movequat)
IF DISPLAYINFO
for c=0 to 3
text 300,10*c,str$(quats(testquat,c),7)
next c
ENDIF
quats(rotquatR,0)=quats(rotquatL,0)
for c=1 to 3
quats(rotquatR,c)=-quats(rotquatL,c)
next c
`get total quaternion by multiplying together the move and rotate quats..
`think i have to reverse rotation order for L and R
`let's just give it a go!
totalqL=4
totalqR=5
_multiply_quaternions(totalqL,rotquatL,movequat)
_multiply_quaternions(totalqR,movequat,rotquatR)
`ADD MOMENTUM!
`want to remember previous total momentum.
`however, if keep this as a quaternion, difficulty in having drag - presumably can raise quaternion to a power (eg 0.99)
`, but i don't know how.
`easier perhaps (although less elegant) to have momentum, angular momentum as 3-vectors. (in player frame)
`not sure how will then have momentum this way for other objects. perhaps in the long run less easy?
`now can do 2 ways.
`intermediate - convert this to matrix and multiply by previous
`my4matrix=10 `arbitrary number
`_convert_quats_to_4matrix(totalqL,totalqR,my4matrix)
`full - multiply this quat by previous, convert that to matrix
_multiply_quaternions(player_qL,totalqL,player_qL)
_multiply_quaternions(player_qR,player_qR,totalqR)
normalise_quat(player_qL) `WORKS FINE WITHOUT THESE
normalise_quat(player_qR) `ONLY REALLY NEED TO CALL ONCE IN A BLUE MOON!
`NICE FOR PEACE OF MIND
`==============================================
`another diagnostic test. try to convert movequat somehow to world frame..
`think only needs 3d rotation. odd..
`PUT CLEVER STUFF HERE. aka guesswork
`this looks okish but it's totally not!
REMSTART
quatrconj=409
quats(quatrconj,0)=quats(player_qR,0)
for c=1 to 3
quats(quatrconj,c)=-quats(player_qR,c)
next c
_multiply_quaternions(testquat,player_qR,movequat)
_multiply_quaternions(testquat,movequat,testquat)
_multiply_quaternions(testquat,testquat,quatrconj)
REMEND
quatlconj=409
quats(quatlconj,0)=quats(player_qL,0)
for c=1 to 3
quats(quatlconj,c)=-quats(player_qL,c)
next c
`_multiply_quaternions(testquat,player_qL,movequat)
`_multiply_quaternions(testquat,testquat,quatlconj)
`^no
_multiply_quaternions(testquat,movequat,player_qL)
_multiply_quaternions(testquat,quatlconj,testquat)
`^^seems to be about half other vel quaternion! have i made trivial error where vel is of 2 steps or something??
_multiply_quaternions(testquat,testquat,testquat) `square it?!
for c=1 to 3
quats(testquat,c)=-quats(testquat,c) `wrong sign for some reason!!!
next c
IF DISPLAYINFO
for c=0 to 3
text 100,100+10*c,str$(quats(testquat,c),7)
text 100+400*quats(testquat,c),200+20*c,"|" `test bars
next c
ENDIF
`difference between this and quat 402 - calculated other way? should be ~0
`either here, or after 402 calculated.
IF DISPLAYINFO
for c=0 to 3
text 100,300+10*c,str$(quats(testquat,c)-quats(402,c),7)
next c
ENDIF
`tere is diff here. as expected - 402 not calculated yet
`==============================================
`shooting quat. add forward velocity
shootquatp=408
shootquatw=407
_copy_quaternion(movequat,shootquatp) `player frame shooting quat. (not moving player frame)
dec quats(shootquatp,1),0.025
tot#=0.0
for c=1 to 3
inc tot#,quats(shootquatp,c)*quats(shootquatp,c)
next c
quats(shootquatp,0)=sqrt(1.0-tot#)
`code from before, but swapped testquat for shootquatw
_multiply_quaternions(shootquatw,shootquatp,player_qL)
_multiply_quaternions(shootquatw,quatlconj,shootquatw)
`^^seems to be about half other vel quaternion! have i made trivial error where vel is of 2 steps or something??
_multiply_quaternions(shootquatw,shootquatw,shootquatw) `square it?!
for c=1 to 3
quats(shootquatw,c)=-quats(shootquatw,c) `wrong sign for some reason!!!
next c
`now convert to rotation matrix, hoping signs are OK!!!!
_convert_quats_to_4matrix(player_qL,player_qR,399) `guess at an unused number
for a=0 to 3:for b=0 to 3 `copy across to old array
mat4#(0, a, b)=matrices(399,a,b)
next b:next a
`fudge this - rotation should change velocity in player frame. not sure what order, r,l etc
if spacekey()<10
_multiply_quaternions(movequat,rotquatL,movequat)
_multiply_quaternions(movequat,movequat,rotquatR)
endif
`^^ by symmetry, should i be rotating rotation by movement somehow???!!
`seems to work OK!!
`probably a way to apply velocity (and retain velocity) in world frame instead.
endfunction
function single_pixel_image(imagenum,red,green,blue,alpha)
temp_memblocknum=1
make memblock temp_memblocknum,16
write memblock dword temp_memblocknum,0,1
write memblock dword temp_memblocknum,4,1
write memblock dword temp_memblocknum,8,32
write memblock dword temp_memblocknum,12,rgba(red,green,blue,alpha)
make image from memblock imagenum,1
delete memblock temp_memblocknum
endfunction
`RGBA function by Aaron Miller
function rgba(r,g,b,a)
c = (a and 0xff) << 24 or ((r and 0xff) << 16) or ((g and 0xff) << 8) or (b and 0xff)
endfunction c
`from random quaternion generator project
function rand_quat_b(q)
ang1#=0.1*rnd(3599)
ang2#=0.1*rnd(3599)
unif=rnd(1000)
`unif#=rnd(1000)*0.001
`t#=sqrt(0) `test root 0 works
`a#=sqrt(unif#)
`b#=sqrt(1.0-unif#)
a#=sqrt(unif*0.001)
b#=sqrt((1000-unif)*0.001)
quats(q,0)=a#*sin(ang1#)
quats(q,1)=a#*cos(ang1#)
quats(q,2)=b#*sin(ang2#)
quats(q,3)=b#*cos(ang2#)
endfunction
`functions from "quaternions test" project. don't need all these just yet, but may as well copy all across.
function _make_random_quaternion(q) `superceded by above. this is a poor random function (makes in a hypercube)
w#=rnd(1001)-500.5
x#=rnd(1001)-500.5
y#=rnd(1001)-500.5
z#=rnd(1001)-500.5
invsize#=1.0/sqrt(w#*w#+x#*x#+y#*y#+z#*z#)
w#=w#*invsize#
x#=x#*invsize#
y#=y#*invsize#
z#=z#*invsize#
quats(q,0)=w#
quats(q,1)=x#
quats(q,2)=y#
quats(q,3)=z#
endfunction
function normalise_quat(q)
w#=quats(q,0)
x#=quats(q,1)
y#=quats(q,2)
z#=quats(q,3)
invsize#=1.0/sqrt(w#*w#+x#*x#+y#*y#+z#*z#)
w#=w#*invsize#
x#=x#*invsize#
y#=y#*invsize#
z#=z#*invsize#
quats(q,0)=w#
quats(q,1)=x#
quats(q,2)=y#
quats(q,3)=z#
endfunction
function _convert_quat_to_matrix(q,m)
a as float
b as float
c as float
d as float
asq as float
bsq as float
csq as float
dsq as float
a=quats(q,0)
b=quats(q,1)
c=quats(q,2)
d=quats(q,3)
asq=a*a
bsq=b*b
csq=c*c
dsq=d*d
matrices(m,1,1)=asq+bsq-csq-dsq :matrices(m,1,2)=2.0*(b*c-a*d) :matrices(m,1,3)=2.0*(b*d+a*c)
matrices(m,2,1)=2.0*(b*c+a*d) :matrices(m,2,2)=asq-bsq+csq-dsq :matrices(m,2,3)=2.0*(c*d-a*b)
matrices(m,3,1)=2.0*(b*d-a*c) :matrices(m,3,2)=2.0*(c*d+a*b) :matrices(m,3,3)=asq-bsq-csq+dsq
endfunction
function _convert_quats_to_4matrix(q1,q2,m)
a1 as float
b1 as float
c1 as float
d1 as float
a2 as float
b2 as float
c2 as float
d2 as float
a1=quats(q1,0)
b1=quats(q1,1)
c1=quats(q1,2)
d1=quats(q1,3)
a2=quats(q2,0)
b2=quats(q2,1)
c2=quats(q2,2)
d2=quats(q2,3)
` aa as float
` bb as float
` cc as float
` dd as float
a1a2#=a1*a2
a1b2#=a1*b2
a1c2#=a1*c2
a1d2#=a1*d2
b1a2#=b1*a2
b1b2#=b1*b2
b1c2#=b1*c2
b1d2#=b1*d2
c1a2#=c1*a2
c1b2#=c1*b2
c1c2#=c1*c2
c1d2#=c1*d2
d1a2#=d1*a2
d1b2#=d1*b2
d1c2#=d1*c2
d1d2#=d1*d2
matrices(m,0,0)=a1a2#-b1b2#-c1c2#-d1d2# :matrices(m,0,1)=-a1b2#-b1a2#+c1d2#-d1c2# :matrices(m,0,2)=-a1c2#-b1d2#-c1a2#+d1b2# :matrices(m,0,3)=-a1d2#+b1c2#-c1b2#-d1a2#
matrices(m,1,0)=b1a2#+a1b2#-d1c2#+c1d2# :matrices(m,1,1)=-b1b2#+a1a2#+d1d2#+c1c2# :matrices(m,1,2)=-b1c2#+a1d2#-d1a2#-c1b2# :matrices(m,1,3)=-b1d2#-a1c2#-d1b2#+c1a2#
matrices(m,2,0)=c1a2#+d1b2#+a1c2#-b1d2# :matrices(m,2,1)=-c1b2#+d1a2#-a1d2#-b1c2# :matrices(m,2,2)=-c1c2#+d1d2#+a1a2#+b1b2# :matrices(m,2,3)=-c1d2#-d1c2#+a1b2#-b1a2#
matrices(m,3,0)=d1a2#-c1b2#+b1c2#+a1d2# :matrices(m,3,1)=-d1b2#-c1a2#-b1d2#+a1c2# :matrices(m,3,2)=-d1c2#-c1d2#+b1a2#-a1b2# :matrices(m,3,3)=-d1d2#+c1c2#+b1b2#+a1a2#
` matrices(m,1,1)=asq+bsq-csq-dsq :matrices(m,1,2)=2.0*(b*c-a*d) :matrices(m,1,3)=2.0*(b*d+a*c)
` matrices(m,2,1)=2.0*(b*c+a*d) :matrices(m,2,2)=asq-bsq+csq-dsq :matrices(m,2,3)=2.0*(c*d-a*b)
` matrices(m,3,1)=2.0*(b*d-a*c) :matrices(m,3,2)=2.0*(c*d+a*b) :matrices(m,3,3)=asq-bsq-csq+dsq
endfunction
function _multiply_quaternions(prod,a,b)
REMSTART
quats(prod,0)=quats(a,0)*quats(b,0)-(quats(a,1)*quats(b,1)+quats(a,2)*quats(b,2)+quats(a,3)*quats(b,3)) `s1s2 - v1.v2
`v ector part of product= s1v2+s2v1+s3v3 +v1 x v2
quats(prod,1)=quats(a,0)*quats(b,1)+quats(b,0)*quats(a,1)+ quats(a,2)*quats(b,3)-quats(a,3)*quats(b,2)
quats(prod,2)=quats(a,0)*quats(b,2)+quats(b,0)*quats(a,2)+ quats(a,3)*quats(b,1)-quats(a,1)*quats(b,3)
quats(prod,3)=quats(a,0)*quats(b,3)+quats(b,0)*quats(a,3)+ quats(a,1)*quats(b,2)-quats(a,2)*quats(b,1)
REMEND
`this verion less efficient, but allows use of prod=a or b
`can use clever code to never need this, but speed not critical.
w#=quats(a,0)*quats(b,0)-(quats(a,1)*quats(b,1)+quats(a,2)*quats(b,2)+quats(a,3)*quats(b,3))
x#=quats(a,0)*quats(b,1)+quats(b,0)*quats(a,1)+ quats(a,2)*quats(b,3)-quats(a,3)*quats(b,2)
y#=quats(a,0)*quats(b,2)+quats(b,0)*quats(a,2)+ quats(a,3)*quats(b,1)-quats(a,1)*quats(b,3)
z#=quats(a,0)*quats(b,3)+quats(b,0)*quats(a,3)+ quats(a,1)*quats(b,2)-quats(a,2)*quats(b,1)
quats(prod,0)=w#
quats(prod,1)=x#
quats(prod,2)=y#
quats(prod,3)=z#
endfunction
function _multiply_matrices(prod,a,b)
for col=1 to 3:for row=1 to 3
matrices(prod,row,col)=0
for i=1 to 3
matrices(prod,row,col)=matrices(prod,row,col)+matrices(a,row,i)*matrices(b,i,col)
next i
next row:next col
endfunction
function _multiply_4matrices(prod,a,b)
for col=0 to 3:for row=0 to 3
matrices(prod,row,col)=0
for i=0 to 3
matrices(prod,row,col)=matrices(prod,row,col)+matrices(a,row,i)*matrices(b,i,col)
next i
next row:next col
endfunction
function _copy_matrix(m_from,m_to)
for i=1 to 3:for j=1 to 3 `only 3x3 copy. use another func for full 4x4 copy
matrices(m_to,i,j)=matrices(m_from,i,j)
next j:next i
endfunction
function _copy_4matrix(m_from,m_to)
for i=0 to 3:for j=0 to 3 `full 4x4 copy
matrices(m_to,i,j)=matrices(m_from,i,j)
next j:next i
endfunction
function _copy_quaternion(q_from,q_to)
for i=0 to 3
quats(q_to,i)=quats(q_from,i)
next i
endfunction
function _init_quaternion(q,w#,x#,y#,z#)
quats(q,0)=w#:quats(q,1)=x#:quats(q,2)=y#:quats(q,3)=z#
endfunction