Code: Select all
; 360° Panorama Viewer
; Benötigt OpenGL und eine equirectangular Panorama-Textur
UseJPEGImageDecoder()
; Konstanten
#SM_MOUSEWHEELPIXELS = 75 ; Windows System Metrics Konstante für Mausrad
#GL_BGR = $80E0
#GL_BGRA = $80E1
Global RollX.f
Global RollY.f
Global MouseX.l
Global MouseY.l
Global LastMouseX.l
Global LastMouseY.l
Global ZoomFactor.f = -5.0
Global IsMouseDown.l = #False
#WINDOW_WIDTH = 1900
#WINDOW_HEIGHT = 1000
#SPHERE_SEGMENTS = 32
; Deklariere Arrays für die Sphere-Daten
Global Dim Vertices.f(#SPHERE_SEGMENTS * #SPHERE_SEGMENTS * 18)
Global Dim TexCoords.f(#SPHERE_SEGMENTS * #SPHERE_SEGMENTS * 12)
Procedure GenerateSphere(radius.f = 1.0)
Protected.f phi, theta, x, y, z, u, v
Protected.l vIndex = 0, tIndex = 0
For lat = 0 To #SPHERE_SEGMENTS - 1
phi1.f = lat * #PI / #SPHERE_SEGMENTS
phi2.f = (lat + 1) * #PI / #SPHERE_SEGMENTS
For lon = 0 To #SPHERE_SEGMENTS - 1
theta1.f = lon * 2 * #PI / #SPHERE_SEGMENTS
theta2.f = (lon + 1) * 2 * #PI / #SPHERE_SEGMENTS
; Erstes Dreieck
; Vertex 1
x = radius * Sin(phi1) * Cos(theta1)
y = radius * Cos(phi1)
z = radius * Sin(phi1) * Sin(theta1)
Vertices(vIndex) = x : vIndex + 1
Vertices(vIndex) = y : vIndex + 1
Vertices(vIndex) = z : vIndex + 1
u = lon / #SPHERE_SEGMENTS
v = lat / #SPHERE_SEGMENTS
TexCoords(tIndex) = u : tIndex + 1
TexCoords(tIndex) = v : tIndex + 1
; Vertex 2
x = radius * Sin(phi2) * Cos(theta1)
y = radius * Cos(phi2)
z = radius * Sin(phi2) * Sin(theta1)
Vertices(vIndex) = x : vIndex + 1
Vertices(vIndex) = y : vIndex + 1
Vertices(vIndex) = z : vIndex + 1
u = lon / #SPHERE_SEGMENTS
v = (lat + 1) / #SPHERE_SEGMENTS
TexCoords(tIndex) = u : tIndex + 1
TexCoords(tIndex) = v : tIndex + 1
; Vertex 3
x = radius * Sin(phi2) * Cos(theta2)
y = radius * Cos(phi2)
z = radius * Sin(phi2) * Sin(theta2)
Vertices(vIndex) = x : vIndex + 1
Vertices(vIndex) = y : vIndex + 1
Vertices(vIndex) = z : vIndex + 1
u = (lon + 1) / #SPHERE_SEGMENTS
v = (lat + 1) / #SPHERE_SEGMENTS
TexCoords(tIndex) = u : tIndex + 1
TexCoords(tIndex) = v : tIndex + 1
; Zweites Dreieck
; Vertex 1
x = radius * Sin(phi1) * Cos(theta1)
y = radius * Cos(phi1)
z = radius * Sin(phi1) * Sin(theta1)
Vertices(vIndex) = x : vIndex + 1
Vertices(vIndex) = y : vIndex + 1
Vertices(vIndex) = z : vIndex + 1
u = lon / #SPHERE_SEGMENTS
v = lat / #SPHERE_SEGMENTS
TexCoords(tIndex) = u : tIndex + 1
TexCoords(tIndex) = v : tIndex + 1
; Vertex 2
x = radius * Sin(phi2) * Cos(theta2)
y = radius * Cos(phi2)
z = radius * Sin(phi2) * Sin(theta2)
Vertices(vIndex) = x : vIndex + 1
Vertices(vIndex) = y : vIndex + 1
Vertices(vIndex) = z : vIndex + 1
u = (lon + 1) / #SPHERE_SEGMENTS
v = (lat + 1) / #SPHERE_SEGMENTS
TexCoords(tIndex) = u : tIndex + 1
TexCoords(tIndex) = v : tIndex + 1
; Vertex 3
x = radius * Sin(phi1) * Cos(theta2)
y = radius * Cos(phi1)
z = radius * Sin(phi1) * Sin(theta2)
Vertices(vIndex) = x : vIndex + 1
Vertices(vIndex) = y : vIndex + 1
Vertices(vIndex) = z : vIndex + 1
u = (lon + 1) / #SPHERE_SEGMENTS
v = lat / #SPHERE_SEGMENTS
TexCoords(tIndex) = u : tIndex + 1
TexCoords(tIndex) = v : tIndex + 1
Next
Next
EndProcedure
Procedure DrawPanorama(Gadget)
SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
glPushMatrix_()
glMatrixMode_(#GL_MODELVIEW)
glTranslatef_(0, 0, ZoomFactor)
glRotatef_(RollX, 1.0, 0, 0)
glRotatef_(RollY, 0, 1.0, 0)
glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
; Zeichne die Sphere mit Textur
glEnable_(#GL_TEXTURE_2D)
glEnableClientState_(#GL_VERTEX_ARRAY)
glEnableClientState_(#GL_TEXTURE_COORD_ARRAY)
glVertexPointer_(3, #GL_FLOAT, 0, @Vertices(0))
glTexCoordPointer_(2, #GL_FLOAT, 0, @TexCoords(0))
; Zeichne alle Dreiecke der Sphere
glDrawArrays_(#GL_TRIANGLES, 0, #SPHERE_SEGMENTS * #SPHERE_SEGMENTS * 6)
glDisableClientState_(#GL_VERTEX_ARRAY)
glDisableClientState_(#GL_TEXTURE_COORD_ARRAY)
glDisable_(#GL_TEXTURE_2D)
glPopMatrix_()
glFinish_()
SetGadgetAttribute(Gadget, #PB_OpenGL_FlipBuffers, #True)
EndProcedure
Procedure SetupGL()
glMatrixMode_(#GL_PROJECTION)
gluPerspective_(75.0, #WINDOW_WIDTH / #WINDOW_HEIGHT, 0.1, 100.0)
glMatrixMode_(#GL_MODELVIEW)
glLoadIdentity_()
glEnable_(#GL_DEPTH_TEST)
glEnable_(#GL_CULL_FACE)
glCullFace_(#GL_BACK)
glShadeModel_(#GL_SMOOTH)
EndProcedure
Procedure SetupGLTexture(ImageHandle.i)
Define.i ImageW, ImageH, ImageD
Define.i MemoryAddress
Define.i TextureHandle
If IsImage(ImageHandle) = 0
ProcedureReturn #False
EndIf
ImageD = ImageDepth(ImageHandle, #PB_Image_InternalDepth)
StartDrawing(ImageOutput(ImageHandle))
MemoryAddress = DrawingBuffer()
StopDrawing()
If MemoryAddress = 0
ProcedureReturn #False
EndIf
glGenTextures_(1, @TextureHandle)
glBindTexture_(#GL_TEXTURE_2D, TextureHandle)
ImageW = ImageWidth(ImageHandle)
ImageH = ImageHeight(ImageHandle)
If ImageD = 32
glTexImage2D_(#GL_TEXTURE_2D, 0, 4, ImageW, ImageH, 0, #GL_BGRA, #GL_UNSIGNED_BYTE, MemoryAddress)
Else
glTexImage2D_(#GL_TEXTURE_2D, 0, 3, ImageW, ImageH, 0, #GL_BGR, #GL_UNSIGNED_BYTE, MemoryAddress)
EndIf
glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_LINEAR)
; glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_LINEAR)
ProcedureReturn TextureHandle
EndProcedure
; Hauptprogramm
If OpenWindow(0, 0, 0, #WINDOW_WIDTH, #WINDOW_HEIGHT, "360° Panorama Viewer", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If OpenGLGadget(0, 0, 0, #WINDOW_WIDTH, #WINDOW_HEIGHT)
SetupGL()
; Sphere generieren
GenerateSphere(5.0)
; Textur laden
If LoadImage(0, "c:\temp\EquiRectangel_Panorama.jpg")
; Bild in RGB-Format konvertieren
SetupGLTexture(0)
FreeImage(0)
EndIf
; Timer für Rendering
AddWindowTimer(0, 1, 16) ; ~60 FPS
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_Timer
If EventTimer() = 1
DrawPanorama(0)
EndIf
Case #WM_LBUTTONDOWN
IsMouseDown = #True
LastMouseX = WindowMouseX(0)
LastMouseY = WindowMouseY(0)
Case #WM_LBUTTONUP
IsMouseDown = #False
Case #WM_MOUSEMOVE
If IsMouseDown
MouseX = WindowMouseX(0)
MouseY = WindowMouseY(0)
If LastMouseX Or LastMouseY
RollY + (MouseX - LastMouseX) * 0.5
RollX + (MouseY - LastMouseY) * 0.5
; Vertikale Rotation begrenzen
If RollX > 89
RollX = 89
ElseIf RollX < -89
RollX = -89
EndIf
EndIf
LastMouseX = MouseX
LastMouseY = MouseY
EndIf
Case #WM_MOUSEWHEEL
WheelDelta = GetSystemMetrics_(#SM_MOUSEWHEELPIXELS)
If WheelDelta
ZoomFactor + (WheelDelta / 120) * 0.5
If ZoomFactor > -0.5 : ZoomFactor = -0.5 : EndIf
If ZoomFactor < -20.0 : ZoomFactor = -20.0 : EndIf
EndIf
EndSelect
Until Event = #PB_Event_CloseWindow
; Aufräumen
glDeleteTextures_(1, @texture)
EndIf
CloseWindow(0)
EndIf