General 3D Rotation

Advanced game related topics
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

General 3D Rotation

Post by Foz »

Okay, this isn't a question about code, but of math!

This is my problem. I am at (0,0,0), and I'm looking down the Z axis. When I pitch up or down, I rotate the X axis, and I look up and down. If I then roll, I rotate the Z axis and then I roll accordingly.

My issue is this: if I pitch up or down first, and then try to roll, I can no longer roll on the Z axis as the rotation doesn't work. Another axis needs to be involved, but by how much, and which axis... I do not know.

So, just using pitch and roll, how do I sort out the local rotations?
gnasen
Enthusiast
Enthusiast
Posts: 282
Joined: Wed Sep 24, 2008 12:21 am

Re: General 3D Rotation

Post by gnasen »

Im not absolutly sure what youre problem exactly is. Maybe its just a matter of my bad english skills ;)
However it seems that you try to do different yaw-pitch-roll's in a row and now youre stuck, because the rotation is everytime along the local rotations.
I think its much easier if you dont rpw from the last local point. Instead try to sum up the different angles and use an absolute ypr at every frame.
It may help you too, that the matrice multiplication is not commutative, so it does matter in which order you rotate.
For a rotation along the local axis, you should go by this: rot1 * rot2 * rot3
For a rotation along the fixed axis, you should go by this: rot3 * rot2 * rot1

It would help (me ;) ) much, if you could explain in more detail what youre doing.
pb 5.11
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Re: General 3D Rotation

Post by Foz »

Ok, heres some example code, note that you will have to set the subsystem to opengl:

Code: Select all

Global WallTexture

Structure POINTZ
  x.f
  y.f
  z.f
EndStructure

Global NewList StarField.POINTZ()

For i = 1 To 2500
  AddElement(StarField())
  StarField()\x = Random(200) - 100
  StarField()\y = Random(200) - 100
  StarField()\z = Random(200) - 100
Next

Global Speed.f = 1

Global Pitch.f = 0
Global Roll.f = 0

Global Position.POINTZ
Position\x = 0
Position\y = 0
Position\z = 0


;{--- OpenGL Setup
CompilerIf Subsystem("OpenGL")
CompilerElse
  MessageRequester("ERROR", "Set the subsystem To OpenGL")
  End
CompilerEndIf

; pb workaround fix
Import ""
PB_Screen_Target
EndImport
#GL_TEXTURE_RECTANGLE_ARB        =  $84F5
;----------------------------
#GL_BLEND = $0BE2
#GL_COLOR_BUFFER_BIT = $00004000
#GL_DEPTH_BUFFER_BIT = $00000100
#GL_DEPTH_TEST = $0B71
#GL_LEQUAL = $0203
#GL_LINEAR = $2601
#GL_LINEAR_MIPMAP_NEAREST = $2701
#GL_LUMINANCE = $1909

#GL_UNSIGNED_INT = $1405
#GL_UNSIGNED_INT_8_8_8_8	= $8035
#GL_BGRA = $80E1
#GL_RGBA = $1908
#GL_RGBA8 = $8058

#GL_MODELVIEW = $1700
#GL_MODULATE = $2100
#GL_NICEST = $1102
#GL_PERSPECTIVE_CORRECTION_HINT = $0C50
#GL_PROJECTION = $1701
#GL_SMOOTH = $1D01
#GL_TEXTURE_2D = $0DE1
#GL_TEXTURE_ENV = $2300
#GL_TEXTURE_ENV_MODE = $2200
#GL_TEXTURE_MAG_FILTER = $2800
#GL_TEXTURE_MIN_FILTER = $2801
#GL_TEXTURE_WRAP_S = $2802
#GL_TEXTURE_WRAP_T = $2803
#GL_TRUE = 1
#GL_UNSIGNED_BYTE = $1401

#GL_SRC_ALPHA = $0302
#GL_ONE = 1
#GL_UNPACK_ALIGNMENT = $0CF5

;  BeginMode 
#GL_POINTS                         = $0000
#GL_LINES                          = $0001
#GL_LINE_LOOP                      = $0002
#GL_LINE_STRIP                     = $0003
#GL_TRIANGLES                      = $0004
#GL_TRIANGLE_STRIP                 = $0005
#GL_TRIANGLE_FAN                   = $0006
#GL_QUADS                          = $0007
#GL_QUAD_STRIP                     = $0008
#GL_POLYGON                        = $0009


CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  ImportC "/usr/lib/libX11.a"+Chr('"')+" -l"+Chr('"')+"GL"
CompilerElse
  Import "Opengl32.lib"
CompilerEndIf
;{-
glBegin(a.l)
glBindTexture(a.l,b.l)
glClear(a.l)
glClearColor(a.f,b.f,c.f,d.f)
glClearDepth(a.d)
glDepthFunc(a.l)
glDepthMask(a.c)
glDisable(a.l)
glEnable(a.l)
glEnd()
glGenTextures(a.l,b.l)
glGetError()
glHint(a.l,b.l)
glLoadIdentity()
glMatrixMode(a.l)
glShadeModel(a.l)
glTexCoord2f(a.f,b.f)
glTexEnvf(a.l,b.l,c.f)
glTexParameterf(a.l,b.l,c.f)
glTexParameteri(a.l,b.l,c.i)
glTranslatef(a.f,b.f,c.f)
glVertex3f(a.f,b.f,c.f)
glVertex2f(a.f,b.f)
glViewport(a.l,b.l,c.l,d.l)

glBlendFunc(a.l,b.l) ; As "glBlendFunc@8"
glPixelStorei(a.l,b.l) ; As "glPixelStorei@8"
glColor3f(r.f, g.f, b.f)
glColor4f(r.f, g.f, b.f, a.f)
glRotatef(degrees.f, x.f, y.f, z.f)

glPushMatrix()
glPopMatrix()

glMultMatrixf(*matrix)
;}
EndImport

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  ImportC "/usr/lib/libGLU.a"
CompilerElse
  Import "Glu32.lib"
CompilerEndIf
;{-
gluBuild2DMipmaps(a.l,b.l,c.l,d.l,e.l,f.l,g.l)
gluErrorString(a.l)
gluPerspective(a.d,b.d,c.d,d.d)
gluLookAt(CameraX.f, CameraY.f, CameraZ.f, LookAtX.f, LookAtY.f, LookAtZ.f, UpX.f, UpY.f, UpZ.f)
;}
EndImport
;}

Procedure Noise(x, y)
  Static salt = 0
  salt = salt ! x & y
  ProcedureReturn salt
EndProcedure

Procedure.i GenerateTexture(pWidth.i, pHeight.i)
  Protected img = CreateImage(#PB_Any, pWidth, pHeight, 32)
  
  StartDrawing(ImageOutput(img))
  Protected *mem = DrawingBuffer()
  
  For y = 0 To pHeight-1
    For x = 0 To pWidth-1
      n = Noise(x, y) * 4
      If n < 0   : n = 0   : EndIf
      If n > 255 : n = 255 : EndIf
      Plot(x, y, RGBA(n, n, n, n))
    Next
  Next
  
  DrawingMode(#PB_2DDrawing_Transparent  )
  DrawText(10,10,"Hello", RGBA(255,255,255,255))
  
  StopDrawing()
  
  Protected TexID = 0
  glGenTextures(1, @TexID)
  glBindTexture(#GL_TEXTURE_2D, TexID)
  
  glTexEnvf(#GL_TEXTURE_ENV, #GL_TEXTURE_ENV_MODE, #GL_MODULATE )
  
  ; when texture area is small, bilinear filter the closest mipmap
  glTexParameterf(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_LINEAR_MIPMAP_NEAREST );
  ; when texture area is large, bilinear filter the original
  glTexParameterf(#GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_LINEAR );
  
  rv = gluBuild2DMipmaps(#GL_TEXTURE_2D, 4, pWidth, pHeight, #GL_RGBA, #GL_UNSIGNED_BYTE, *mem ) ;
  
  If rv <> 0
    Debug Str(rv) + " :: " + PeekS(gluErrorString(rv))
    ProcedureReturn 0
  EndIf
  
  ProcedureReturn TexID
EndProcedure

Procedure InitGL()
  glClearColor(0.0, 0.0, 0.0, 0.0)
  
  glEnable(#GL_TEXTURE_2D)
  glEnable(#GL_BLEND)
  
  glBlendFunc(#GL_SRC_ALPHA, #GL_ONE);
  glPixelStorei(#GL_UNPACK_ALIGNMENT, 1);
  
  glShadeModel(#GL_SMOOTH)
  glClearDepth(1.0)
  glEnable(#GL_DEPTH_TEST)
  glDepthMask(#GL_TRUE);
  glDepthFunc(#GL_LEQUAL)
  glHint(#GL_PERSPECTIVE_CORRECTION_HINT, #GL_NICEST)
EndProcedure

Procedure ResizeScene(width, height)
  If height < 1 : height = 1 : EndIf
  If width < 1 : width = 1 : EndIf
  
  glViewport(0, 0, width, height)
  glMatrixMode(#GL_PROJECTION)
  glLoadIdentity()
  
  gluPerspective(45, width / height, 0,  100)
  
  glMatrixMode(#GL_MODELVIEW)
  glLoadIdentity()
EndProcedure

Procedure DrawScene()
  glClear(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
  
  glLoadIdentity()
  
  glRotatef(Pitch, 1, 0, 0)
  glRotatef(Roll, 0, 0, 1)
  

  glEnable(#GL_TEXTURE_2D)
  glBindTexture(#GL_TEXTURE_2D, WallTexture)
  
  glPushMatrix()
  
  glTranslatef(0, 0, -5)
  glBegin(#GL_QUADS);
  
  glTexCoord2f(0.0, 0.0);
  glVertex3f(0.0, 0.0,  1.0);   // Bottom Left Of The Texture and Quad
  glTexCoord2f(1.0, 0.0);
  glVertex3f( 1.0, 0.0,  1.0);   // Bottom Right Of The Texture and Quad
  glTexCoord2f(1.0, 1.0);
  glVertex3f( 1.0,  1.0,  1.0);   // Top Right Of The Texture and Quad
  glTexCoord2f(0.0, 1.0);
  glVertex3f(0.0,  1.0,  1.0);   // Top Left Of The Texture and Quad
  
  glEnd( );
  glPopMatrix()
  
  
  glDisable(#GL_TEXTURE_2D);
  
  glPushMatrix()
  glBegin(#GL_POINTS)
  ForEach StarField()
    c.f = 1
    glColor4f(c,c,c,c)
    glVertex3f( StarField()\x, StarField()\y, StarField()\z )
  Next
  glEnd()
  glPopMatrix()
  
  
  With Position
    glTranslatef(\x, \y, \z)
  EndWith
  
EndProcedure

InitSprite() : InitKeyboard()
OpenWindow (0, 100, 100, 512, 512, "OpenGL Window")
OpenWindowedScreen(WindowID(0), 0, 0, 512, 512, 0, 0, 0, #PB_Screen_WaitSynchronization)

glDisable(#GL_TEXTURE_RECTANGLE_ARB)
PB_Screen_Target = #GL_TEXTURE_2D

; load textures
#width = 64
#height = 64

WallTexture = GenerateTexture(#width, #height)

InitGL()

Repeat
  TimerStart = ElapsedMilliseconds()
  
  Select WindowEvent()
    Case #PB_Event_CloseWindow
      Break
  EndSelect
  
  ExamineKeyboard()
  If KeyboardReleased(#PB_Key_Escape)
    Break
  EndIf
  
  If KeyboardPushed(#PB_Key_Up)
    Pitch + 1
  EndIf
  If KeyboardPushed(#PB_Key_Down)
    Pitch - 1
  EndIf
  
  If KeyboardPushed(#PB_Key_Left)
    Roll - 1
  EndIf
  If KeyboardPushed(#PB_Key_Right)
    Roll + 1
  EndIf
  
  If Pitch < 0
    Pitch = 359.9
  EndIf
  If Pitch > 359.9
    Pitch = 0
  EndIf
  
  If Roll < 0
    Roll = 359.9
  EndIf
  If Roll > 359.9
    Roll = 0
  EndIf
  
  DrawScene()
  
  FlipBuffers()
  ResizeScene(WindowWidth(0), WindowHeight(0))
  
  Repeat
    glError = glGetError()
    Select glError
      Case 0
        Break
      Default
        Debug glError ; + " :: " + PeekS(gluErrorString(glError))
    EndSelect
  ForEver
  
  Pausing = Int((1000.0 / 60.0) - (ElapsedMilliseconds() - TimerStart))
  If Pausing < 1 : Pausing = 1 : EndIf
  Delay( Pausing )
  
  
ForEver
Ok, now if you pitch up and down and return to the centre, and then roll and return to the centre, that is how I want it to look, regardless of which way I am pointing.

However, if I pitch down and then roll, you will see that I am still rotating about on the global axis.

How do I solve that?
DarkDragon
Addict
Addict
Posts: 2348
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: General 3D Rotation

Post by DarkDragon »

The compiler crashes here when trying to run this. (Windows 7, PB 4.50 x64)
bye,
Daniel
gnasen
Enthusiast
Enthusiast
Posts: 282
Joined: Wed Sep 24, 2008 12:21 am

Re: General 3D Rotation

Post by gnasen »

DarkDragon wrote:The compiler crashes here when trying to run this. (Windows 7, PB 4.50 x64)
Hm runs fine with WinXP PB4.51, did you enable "opengl" subsystem?

I think I found your problem:
glRotatef(angle,x,y,z) seems to rotate around the given vector. Youre given vector is one time the x, one time the z axis. So you rotate allways around the global axis.
If you want to rotate around the local axis, you have to look for a command for local axis rotation (I dont know the gl commands, sry) or compute the rotational vector on your own. (just a guess, but I think the coloumns of your rotation matrix should contain the local x/y/z axis)
pb 5.11
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Re: General 3D Rotation

Post by Foz »

yeah, it's the local rotate that's screwing me over - from what I can see, I have to implement it myself, but I'm lacking the necessary maths to calculate it - hence the question.
gnasen
Enthusiast
Enthusiast
Posts: 282
Joined: Wed Sep 24, 2008 12:21 am

Re: General 3D Rotation

Post by gnasen »

if there is no local rotation or something like that, I would instantly switch the 3d engine... That are absolutly basic commands.
pb 5.11
DarkDragon
Addict
Addict
Posts: 2348
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: General 3D Rotation

Post by DarkDragon »

gnasen wrote:
DarkDragon wrote:The compiler crashes here when trying to run this. (Windows 7, PB 4.50 x64)
Hm runs fine with WinXP PB4.51, did you enable "opengl" subsystem?
Yes I did. I even updated PureBasic to PB 4.51 and it still crashes.
With x86 it works well.

Btw.: OpenGL is not a 3d engine but a renderer. Its on the same level as direct3d.
bye,
Daniel
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Re: General 3D Rotation

Post by Foz »

That sounds like a 32 bit/64 bit pointer conflict. Hmmm. I'll look at that when I get home.
DarkDragon
Addict
Addict
Posts: 2348
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: General 3D Rotation

Post by DarkDragon »

But the compiler shouldn't crash.

Nevertheless you may want to have a look at "Rotation about an arbitrary axis" - a topic discussed in many books and on many websites. Or you should use gluLookAt instead. The mathematics are essential and you won't get around it.
bye,
Daniel
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Re: General 3D Rotation

Post by Foz »

Well, I've fixed it. It's taken 3 days of head smashing and now something clicked. I wasn't keeping a track of my current rotation. And how should one keep a track of 3D rotations? Enter Quaternion's.

Simply put, whenever I need to rotate, I have to apply it to the my previous rotation, and Quaternion's do this very well. That and most of the Quaternion code was previously written on the forums by someone else. :)

I am sure that there are other (probably better) ways of doing this, and if you can, please tell all!

Code: Select all

Global WallTexture

Structure Matrix4
  W1.f
  X1.f
  Y1.f
  Z1.f
  W2.f
  X2.f
  Y2.f
  Z2.f
  W3.f
  X3.f
  Y3.f
  Z3.f
  W4.f
  X4.f
  Y4.f
  Z4.f
EndStructure

Structure QUATERNION
  X.f
  Y.f
  Z.f
  w.f
EndStructure

Procedure Quaternion_ToMatrix(*ReturnMatrix.Matrix4, *q.QUATERNION)
	*ReturnMatrix\W1 = 1.0 - 2.0 * ( *q\Y * *q\Y + *q\Z * *q\Z );
	*ReturnMatrix\X1 = 2.0 * (*q\X * *q\Y + *q\Z * *q\w);
	*ReturnMatrix\Y1 = 2.0 * (*q\X * *q\Z - *q\Y * *q\w);
	*ReturnMatrix\Z1 = 0.0;
	
	; Second row
	*ReturnMatrix\W2 = 2.0 * ( *q\X * *q\Y - *q\Z * *q\w );
	*ReturnMatrix\X2 = 1.0 - 2.0 * ( *q\X * *q\X + *q\Z * *q\Z );
	*ReturnMatrix\Y2 = 2.0 * (*q\Z * *q\Y + *q\X * *q\w );
	*ReturnMatrix\Z2 = 0.0;

	; Third row
	*ReturnMatrix\W3 = 2.0 * ( *q\X * *q\Z + *q\Y * *q\w );
	*ReturnMatrix\X3 = 2.0 * ( *q\Y * *q\Z - *q\X * *q\w );
	*ReturnMatrix\Y3 = 1.0 - 2.0 * ( *q\X * *q\X + *q\Y * *q\Y );
	*ReturnMatrix\Z3 = 0.0;

	; Fourth row
	*ReturnMatrix\W4 = 0;
	*ReturnMatrix\X4 = 0;
	*ReturnMatrix\Y4 = 0;
	*ReturnMatrix\Z4 = 1.0;
EndProcedure

Procedure.f Quaternion_Length(*TempQuat.QUATERNION)
  ProcedureReturn Sqr(Pow(*TempQuat\X,2) + Pow(*TempQuat\Y,2) + Pow(*TempQuat\Z,2) + Pow(*TempQuat\w,2))
EndProcedure

Procedure Quaternion_Multiply(*NewQuat.QUATERNION, *Quat1.QUATERNION, *Quat2.QUATERNION)
  *NewQuat\w = *Quat1\w * *Quat2\w - *Quat1\X * *Quat2\X - *Quat1\Y * *Quat2\Y - *Quat1\Z * *Quat2\Z
  *NewQuat\X = *Quat1\w * *Quat2\X + *Quat1\X * *Quat2\w + *Quat1\Y * *Quat2\Z - *Quat1\Z * *Quat2\Y
  *NewQuat\Y = *Quat1\w * *Quat2\Y + *Quat1\Y * *Quat2\w + *Quat1\Z * *Quat2\X - *Quat1\X * *Quat2\Z
  *NewQuat\Z = *Quat1\w * *Quat2\Z + *Quat1\Z * *Quat2\w + *Quat1\X * *Quat2\Y - *Quat1\Y * *Quat2\X
EndProcedure

Procedure Quaternion_Normalize(*TempQuat.QUATERNION)
  TEMP_length.f = Quaternion_Length(*TempQuat)
  *TempQuat\X = *TempQuat\X / TEMP_length
  *TempQuat\Y = *TempQuat\Y / TEMP_length
  *TempQuat\Z = *TempQuat\Z / TEMP_length
  *TempQuat\w = *TempQuat\w / TEMP_length
EndProcedure

Procedure Quaternion_FromAngleAxis(*TempQuat.QUATERNION, X.f, Y.f, Z.f, angleDegrees.f)
  If X = 0 And Y = 0 And Z = 0
    *TempQuat\X = 0
    *TempQuat\Y = 0
    *TempQuat\Z = 0
    *TempQuat\w = 1
    ProcedureReturn 0
  EndIf
  
  TEMP_angle.f = angleDegrees * 0.01745329
  TEMP_angle = TEMP_angle / 2
  TEMP_scale.f = Sin(TEMP_angle)
  
  *TempQuat\X = X * TEMP_scale
  *TempQuat\Y = Y * TEMP_scale
  *TempQuat\Z = Z * TEMP_scale
  *TempQuat\w = Cos(TEMP_angle)
  
  Quaternion_Normalize(*TempQuat)
EndProcedure


Structure POINTZ
  x.f
  y.f
  z.f
EndStructure

Global NewList StarField.POINTZ()

For i = 1 To 2500
  AddElement(StarField())
  StarField()\x = Random(200) - 100
  StarField()\y = Random(200) - 100
  StarField()\z = Random(200) - 100
Next

Global Speed.f = 1

Global Pitch.f = 0
Global Roll.f = 0

Global Position.POINTZ
Position\x = 0
Position\y = 0
Position\z = 0

Global qRotation.QUATERNION
qRotation\w = 1
qRotation\X = 0
qRotation\Y = 0
qRotation\Z = 0

;{--- OpenGL Setup
CompilerIf Subsystem("OpenGL")
CompilerElse
  MessageRequester("ERROR", "Set the subsystem To OpenGL")
  End
CompilerEndIf

; pb workaround fix
Import ""
PB_Screen_Target
EndImport
#GL_TEXTURE_RECTANGLE_ARB        =  $84F5
;----------------------------
#GL_BLEND = $0BE2
#GL_COLOR_BUFFER_BIT = $00004000
#GL_DEPTH_BUFFER_BIT = $00000100
#GL_DEPTH_TEST = $0B71
#GL_LEQUAL = $0203
#GL_LINEAR = $2601
#GL_LINEAR_MIPMAP_NEAREST = $2701
#GL_LUMINANCE = $1909

#GL_UNSIGNED_INT = $1405
#GL_UNSIGNED_INT_8_8_8_8   = $8035
#GL_BGRA = $80E1
#GL_RGBA = $1908
#GL_RGBA8 = $8058

#GL_MODELVIEW = $1700
#GL_MODULATE = $2100
#GL_NICEST = $1102
#GL_PERSPECTIVE_CORRECTION_HINT = $0C50
#GL_PROJECTION = $1701
#GL_SMOOTH = $1D01
#GL_TEXTURE_2D = $0DE1
#GL_TEXTURE_ENV = $2300
#GL_TEXTURE_ENV_MODE = $2200
#GL_TEXTURE_MAG_FILTER = $2800
#GL_TEXTURE_MIN_FILTER = $2801
#GL_TEXTURE_WRAP_S = $2802
#GL_TEXTURE_WRAP_T = $2803
#GL_TRUE = 1
#GL_UNSIGNED_BYTE = $1401

#GL_SRC_ALPHA = $0302
#GL_ONE = 1
#GL_UNPACK_ALIGNMENT = $0CF5

;  BeginMode
#GL_POINTS                         = $0000
#GL_LINES                          = $0001
#GL_LINE_LOOP                      = $0002
#GL_LINE_STRIP                     = $0003
#GL_TRIANGLES                      = $0004
#GL_TRIANGLE_STRIP                 = $0005
#GL_TRIANGLE_FAN                   = $0006
#GL_QUADS                          = $0007
#GL_QUAD_STRIP                     = $0008
#GL_POLYGON                        = $0009


CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  ImportC "/usr/lib/libX11.a"+Chr('"')+" -l"+Chr('"')+"GL"
CompilerElse
  Import "Opengl32.lib"
CompilerEndIf
;{-
glBegin(a.l)
glBindTexture(a.l,b.l)
glClear(a.l)
glClearColor(a.f,b.f,c.f,d.f)
glClearDepth(a.d)
glDepthFunc(a.l)
glDepthMask(a.c)
glDisable(a.l)
glEnable(a.l)
glEnd()
glGenTextures(a.l,b.l)
glGetError()
glHint(a.l,b.l)
glLoadIdentity()
glMatrixMode(a.l)
glShadeModel(a.l)
glTexCoord2f(a.f,b.f)
glTexEnvf(a.l,b.l,c.f)
glTexParameterf(a.l,b.l,c.f)
glTexParameteri(a.l,b.l,c.i)
glTranslatef(a.f,b.f,c.f)
glVertex3f(a.f,b.f,c.f)
glVertex2f(a.f,b.f)
glViewport(a.l,b.l,c.l,d.l)

glBlendFunc(a.l,b.l) ; As "glBlendFunc@8"
glPixelStorei(a.l,b.l) ; As "glPixelStorei@8"
glColor3f(r.f, g.f, b.f)
glColor4f(r.f, g.f, b.f, a.f)
glRotatef(degrees.f, x.f, y.f, z.f)

glPushMatrix()
glPopMatrix()

glMultMatrixf(*matrix)
;}
EndImport

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  ImportC "/usr/lib/libGLU.a"
CompilerElse
  Import "Glu32.lib"
CompilerEndIf
;{-
gluBuild2DMipmaps(a.l,b.l,c.l,d.l,e.l,f.l,g.l)
gluErrorString(a.l)
gluPerspective(a.d,b.d,c.d,d.d)
gluLookAt(CameraX.f, CameraY.f, CameraZ.f, LookAtX.f, LookAtY.f, LookAtZ.f, UpX.f, UpY.f, UpZ.f)
;}
EndImport
;}

Procedure Noise(x, y)
  Static salt = 0
  salt = salt ! x & y
  ProcedureReturn salt
EndProcedure

Procedure.i GenerateTexture(pWidth.i, pHeight.i)
  Protected img = CreateImage(#PB_Any, pWidth, pHeight, 32)
 
  StartDrawing(ImageOutput(img))
  Protected *mem = DrawingBuffer()
 
  For y = 0 To pHeight-1
    For x = 0 To pWidth-1
      n = Noise(x, y) * 4
      If n < 0   : n = 0   : EndIf
      If n > 255 : n = 255 : EndIf
      Plot(x, y, RGBA(n, n, n, n))
    Next
  Next
 
  DrawingMode(#PB_2DDrawing_Transparent  )
  DrawText(10,10,"Hello", RGBA(255,255,255,255))
 
  StopDrawing()
 
  Protected TexID = 0
  glGenTextures(1, @TexID)
  glBindTexture(#GL_TEXTURE_2D, TexID)
 
  glTexEnvf(#GL_TEXTURE_ENV, #GL_TEXTURE_ENV_MODE, #GL_MODULATE )
 
  ; when texture area is small, bilinear filter the closest mipmap
  glTexParameterf(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_LINEAR_MIPMAP_NEAREST );
  ; when texture area is large, bilinear filter the original
  glTexParameterf(#GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_LINEAR );
 
  rv = gluBuild2DMipmaps(#GL_TEXTURE_2D, 4, pWidth, pHeight, #GL_RGBA, #GL_UNSIGNED_BYTE, *mem ) ;
 
  If rv <> 0
    Debug Str(rv) + " :: " + PeekS(gluErrorString(rv))
    ProcedureReturn 0
  EndIf
 
  ProcedureReturn TexID
EndProcedure

Procedure InitGL()
  glClearColor(0.0, 0.0, 0.0, 0.0)
 
  glEnable(#GL_TEXTURE_2D)
  glEnable(#GL_BLEND)
 
  glBlendFunc(#GL_SRC_ALPHA, #GL_ONE);
  glPixelStorei(#GL_UNPACK_ALIGNMENT, 1);
 
  glShadeModel(#GL_SMOOTH)
  glClearDepth(1.0)
  glEnable(#GL_DEPTH_TEST)
  glDepthMask(#GL_TRUE);
  glDepthFunc(#GL_LEQUAL)
  glHint(#GL_PERSPECTIVE_CORRECTION_HINT, #GL_NICEST)
EndProcedure

Procedure ResizeScene(width, height)
  If height < 1 : height = 1 : EndIf
  If width < 1 : width = 1 : EndIf
 
  glViewport(0, 0, width, height)
  glMatrixMode(#GL_PROJECTION)
  glLoadIdentity()
 
  gluPerspective(45, width / height, 0,  100)
 
  glMatrixMode(#GL_MODELVIEW)
  glLoadIdentity()
EndProcedure

Procedure DrawScene()
  glClear(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
 
  glLoadIdentity()
 
  If Roll <> 0 Or Pitch <> 0
    Protected qResult.QUATERNION
    Protected qPitch.QUATERNION
    Protected qRoll.QUATERNION
    Quaternion_FromAngleAxis(@qRoll, 0,0,1, Roll)
    Quaternion_Multiply(@qResult, @qRoll, @qRotation)
    CopyStructure(@qResult, @qRotation, QUATERNION)
    
    Quaternion_FromAngleAxis(@qPitch, 1,0,0, Pitch)
    Quaternion_Multiply(@qResult, @qPitch, @qRotation)
    CopyStructure(@qResult, @qRotation, QUATERNION)
    
    Roll = 0
    Pitch = 0
  EndIf
  
  Protected m.Matrix4
  Quaternion_ToMatrix(@m, @qRotation)
  glMultMatrixf(@m)

  glEnable(#GL_TEXTURE_2D)
  glBindTexture(#GL_TEXTURE_2D, WallTexture)
 
  glPushMatrix()
 
  glTranslatef(0, 0, -5)
  glBegin(#GL_QUADS);
 
  glTexCoord2f(0.0, 0.0);
  glVertex3f(0.0, 0.0,  1.0);   // Bottom Left Of The Texture and Quad
  glTexCoord2f(1.0, 0.0);
  glVertex3f( 1.0, 0.0,  1.0);   // Bottom Right Of The Texture and Quad
  glTexCoord2f(1.0, 1.0);
  glVertex3f( 1.0,  1.0,  1.0);   // Top Right Of The Texture and Quad
  glTexCoord2f(0.0, 1.0);
  glVertex3f(0.0,  1.0,  1.0);   // Top Left Of The Texture and Quad
 
  glEnd( );
  glPopMatrix()
 
 
  glDisable(#GL_TEXTURE_2D);
 
  glPushMatrix()
  glBegin(#GL_POINTS)
  ForEach StarField()
    c.f = 1
    glColor4f(c,c,c,c)
    glVertex3f( StarField()\x, StarField()\y, StarField()\z )
  Next
  glEnd()
  glPopMatrix()

EndProcedure

InitSprite() : InitKeyboard()
OpenWindow (0, 100, 100, 512, 512, "OpenGL Window")
OpenWindowedScreen(WindowID(0), 0, 0, 512, 512, 0, 0, 0, #PB_Screen_WaitSynchronization)

glDisable(#GL_TEXTURE_RECTANGLE_ARB)
PB_Screen_Target = #GL_TEXTURE_2D

; load textures
#width = 64
#height = 64

WallTexture = GenerateTexture(#width, #height)

InitGL()

Repeat
  TimerStart = ElapsedMilliseconds()
 
  Select WindowEvent()
    Case #PB_Event_CloseWindow
      Break
  EndSelect
 
  ExamineKeyboard()
  If KeyboardReleased(#PB_Key_Escape)
    Break
  EndIf
 
  If KeyboardPushed(#PB_Key_Up)
    Pitch + 1
  EndIf
  If KeyboardPushed(#PB_Key_Down)
    Pitch - 1
  EndIf
 
  If KeyboardPushed(#PB_Key_Left)
    Roll - 1
  EndIf
  If KeyboardPushed(#PB_Key_Right)
    Roll + 1
  EndIf
 
  DrawScene()
 
  FlipBuffers()
  ResizeScene(WindowWidth(0), WindowHeight(0))
 
  Repeat
    glError = glGetError()
    Select glError
      Case 0
        Break
      Default
        Debug glError ; + " :: " + PeekS(gluErrorString(glError))
    EndSelect
  ForEver
 
  Pausing = Int((1000.0 / 60.0) - (ElapsedMilliseconds() - TimerStart))
  If Pausing < 1 : Pausing = 1 : EndIf
  Delay( Pausing )
 
 
ForEver
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Re: General 3D Rotation

Post by Foz »

I cannot get the compiler to crash using this program and the x64 version. I don't know if it's my "hacks" that I'm doing to override some PB internal settings (namely "PB_Screen_Target") or if it's some setting that you have by default on the compiler options.

Anyone else getting a compiler error? And what is the error you get?
Post Reply