Announcement

Collapse

Maintenance

The forum could be offline for 30-60 minutes in the very near future for maintenance (said 3pm Pacific). I was behind on getting this notice. I do apologize.
See more
See less

gbs_00586 Extension Comet viewer

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • gbs_00586 Extension Comet viewer

    I've extended Gary's gbs_00586 with an .obj viewer facility .
    Code is shown hereunder .
    It should be sufficient to go to the http://sci.esa.int/rosetta/54728-sha...-of-comet-67p/ site , download the ESA_Rosetta_OSIRIS_67P_SHAP2P.obj file , save it on disc and run the code .
    As the code uses OpenGl "gl.inc", "glu.inc" should be included .
    Many thanks to Gary , José and Patrice for providiing example codes I've used here.

    Edit : The program should work with other .obj files holding the shape data of other objects , if the data structure matches the format v x y z and f i j k for the vertices and faces respectively

    Code:
    ' fk 67P Comet OpenGL example   07/04/2015
    ' This code was derived from Gary Beenes' : gbs_00586 code Date: 03-10-2012
    ' T added the Comet option , which reads a data file holding the comets 67P mesh
    ' This file is  the .obj file which can be found here : http://sci.esa.int/rosetta/54728-sha...-of-comet-67p/
    ' Just save the file as it comes
     #COMPILER PBWIN 9, PBWIN 10
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "win32api.inc"
    #INCLUDE "gl.inc"
    #INCLUDE "glu.inc"
     %ID_Timer = 1001 : %ID_Label = 1002
     GLOBAL hDlg, hDC, hRC, hLabel AS DWORD
    GLOBAL scalefactor AS SINGLE
    GLOBAL LightPosition(),LightPosition2() AS SINGLE
    GLOBAL x(),y(),z() AS SINGLE
    GLOBAL f() AS LONG
    GLOBAL fn() AS SINGLE
    GLOBAL vertices&,faces&
     FUNCTION PBMAIN() AS LONG
        DIALOG NEW PIXELS, 0, "OpenGL Example 67P Comet",,, 500, 400,%WS_OVERLAPPEDWINDOW TO hDlg
        CONTROL ADD LABEL, hdlg, %ID_Label,"",110,10,100,100, %WS_CHILD OR %WS_VISIBLE OR %SS_SUNKEN OR %SS_NOTIFY
        CONTROL ADD OPTION, hdlg, 505,"Comet",10,110,100,20
        CONTROL ADD OPTION, hdlg, 506,"Triangle_Strip",10,130,100,20
        CONTROL ADD OPTION, hdlg, 507,"Quads",10,150,100,20
        CONTROL SET OPTION  hDlg, 505, 506, 507
        DIALOG SHOW MODAL hdlg CALL dlgproc
    END FUNCTION
    '---------------------------------------------------------------------'
    CALLBACK FUNCTION dlgproc()
        LOCAL pt AS POINT
        LOCAL XDelta, YDelta AS SINGLE
        STATIC SpinInWork,XLast,YLast AS LONG
         SELECT CASE CB.MSG
           CASE %WM_INITDIALOG : GetRenderContext
              InitializeScene
              SetTimer(hDlg, %ID_Timer, 50, %NULL)
              ScaleFactor = 1
              Readmodel
           CASE %WM_COMMAND    : IF CB.CTL > 504 AND CB.CTL < 508 THEN DrawScene 0,0,0
           CASE %WM_TIMER      : DrawScene 0,1,0  'redraw with rotation on y-axiss
           CASE %WM_PAINT      : DrawScene 0,0,0  'redraw with no rotation
           CASE %WM_SIZE       : CONTROL SET SIZE hDlg, %ID_Label, LO(WORD, CB.LPARAM)-120, HI(WORD, CB.LPARAM)-20
              ResizeScene LO(WORD, CB.LPARAM)-120, HI(WORD, CB.LPARAM)-20
              DrawScene 0,0,0  'redraw with no rotation
           CASE %WM_CLOSE      : wglmakecurrent %null, %null 'unselect rendering context
              wgldeletecontext hRC        'delete the rendering context
              releasedc hDlg, hDC         'release device context
           CASE %WM_MOUSEWHEEL
              SELECT CASE HI(INTEGER,CB.WPARAM)
                 CASE > 0  : ScaleFactor = ScaleFactor + 0.1 : DrawScene 0,0,0
                 CASE < 0  : ScaleFactor = ScaleFactor - 0.1 : DrawScene 0,0,0
              END SELECT
           CASE %WM_SetCursor
              GetCursorPos pt          'p.x and p.y are in screen coordinates
              ScreenToClient hDlg, pt  'p.x and p.y are now dialog client coordinates
              IF GetDlgCtrlID(ChildWindowFromPoint( hDlg, pt )) <> %ID_Label THEN EXIT FUNCTION
              SELECT CASE HI(WORD, CB.LPARAM)
                 CASE %WM_LBUTTONDOWN
                    GetCursorPos pt              'pt has xy screen coordinates
                    ScreenToClient hDlg, pt       'pt now has dialog client coordinates
                    IF pt.y < 0 THEN EXIT SELECT
                    KillTimer CB.HNDL, %ID_Timer
                    SpinInWork = 1
                    XLast = Pt.x
                    YLast = Pt.y
                 CASE %WM_MOUSEMOVE
                    IF SpinInWork THEN
                       GetCursorPos pt           'pt has xy screen coordinates
                       ScreenToClient hDlg, pt    'pt now has dialog client coordinates
                       IF pt.y < 0 THEN EXIT SELECT
                       XDelta = XLast - Pt.x
                       YDelta = YLast - Pt.y
                       DrawScene -YDelta, -XDelta, 0
                       XLast = pt.x
                       YLast = pt.y
                    END IF
                 CASE %WM_LBUTTONUP
                    SpinInWork = 0
                    SetTimer(hDlg, %ID_Timer, 50, %NULL)
              END SELECT
        END SELECT
    END FUNCTION
    '---------------------------------------------------------------------'
    SUB GetRenderContext
        LOCAL pfd AS PIXELFORMATDESCRIPTOR   'pixel format properties for device context
        pfd.nSize       =  SIZEOF(PIXELFORMATDESCRIPTOR)
        pfd.nVersion    =  1
        pfd.dwFlags     = %pfd_draw_to_window OR %pfd_support_opengl OR %pfd_doublebuffer
        pfd.dwlayermask = %pfd_main_plane
        pfd.iPixelType  = %pfd_type_rgba
        pfd.ccolorbits  = 24
        pfd.cdepthbits  = 24
         CONTROL HANDLE hdlg, %ID_Label TO hLabel
        hDC = GetDC(hLabel)
        SetPixelFormat(hDC, ChoosePixelFormat(hDC, pfd), pfd)  'set properties of device context
        hRC = wglCreateContext (hDC)                           'get rendering context
        wglMakeCurrent hDC, hRC                                'make the RC current
    END SUB
    '---------------------------------------------------------------------'
    SUB InitializeScene
        glClearColor 0,0,0,0     'sets color to be used with glClear
        glClearDepth 1           'sets zvalue to be used with glClear
        DIM LightDiffuse(3) AS SINGLE:  ARRAY ASSIGN LightDiffuse()  = 0.3, 0.3, 0.3, 1.0
        DIM LightAmbient(3) AS SINGLE:  ARRAY ASSIGN LightAmbient()  = 0.3, 0.3, 0.3, 1.0
        DIM LightPosition(3) AS SINGLE: ARRAY ASSIGN LightPosition() = 5.0, 5.0, 5.0, 1.0
        'CALL glLightfv(%GL_LIGHT0, %GL_DIFFUSE, LightDiffuse(0))     ' Setup The Diffuse Light
        CALL glLightfv(%GL_LIGHT0, %GL_Ambient, LightAmbient(0))     ' Setup The Ambient Light
        CALL glLightfv(%GL_LIGHT0, %GL_POSITION,  LightPosition(0))  ' Position The Light
        CALL glEnable(%GL_LIGHT0)                                    ' Enable Light Zero
        CALL glEnable(%GL_LIGHTING)                                  ' Enable Lighting
        CALL glEnable(%GL_COLOR_MATERIAL)                            ' Enable Coloring Of Material
        CALL glColorMaterial(%GL_FRONT AND %GL_BACK, %GL_AMBIENT_AND_DIFFUSE)
         glDepthFunc %gl_less                                'specify how depth-buffer comparisons are made
        glEnable %gl_depth_test                             'enable depth testing
        glShadeModel %gl_nicest '%gl_smooth                 'smooth shading or nicest
        glHint %gl_perspective_correction_hint, %gl_nicest  'best quality rendering
    END SUB
    '---------------------------------------------------------------------'
    SUB ResizeScene (w AS LONG, h AS LONG)
        glViewport 0, 0, w, h             'resize viewport to match window size
        glMatrixMode %gl_projection       'select the projection matrix
        glLoadIdentity                    'reset the projection matrix
        gluPerspective 45, w/h, 0.1, 100  'calculate the aspect ratio of the Window
        glMatrixMode %gl_modelview        'select the modelview matrix
    END SUB
    '---------------------------------------------------------------------'
    SUB DrawScene (dx AS SINGLE, dy AS SINGLE, dz AS SINGLE)
        STATIC anglex, angley, anglez AS SINGLE
        LOCAL i,j,k,r AS LONG
        FOR i = 1 TO 3
           CONTROL GET CHECK hDlg, 504+i TO j
           IF j = %True THEN EXIT FOR
        NEXT i
         glClear %gl_color_buffer_bit OR %gl_depth_buffer_bit  'clear buffers
        glLoadIdentity               'clear the modelview matrix
        gluLookAt 0,0,10,0,0,0,0,1,0
         glScalef scalefactor, scalefactor, scalefactor
         anglex = anglex + dx : glRotatef anglex, 1,0,0
        angley = angley + dy : glRotatef angley, 0,1,0
        anglez = anglez + dz : glRotatef anglez, 0,0,1
         SELECT CASE i
           CASE 1
              FOR k=1 TO faces&
              r=250
              glBegin %gl_triangles
              glcolor3ub r,r-20,r-20                        'almost white color , added some red
              glNormal3f(fn(k,1),fn(k,3),fn(k,3))           'normals in order to allow shading effects
              glvertex3f  x(f(k,1)),y(f(k,1)),z(f(k,1))     'vertex1
              glvertex3f  x(f(k,2)),y(f(k,2)),z(f(k,2))     'vertex2
              glvertex3f  x(f(k,3)),y(f(k,3)),z(f(k,3))    'vertex3
              glEnd
              NEXT k
           CASE 2
              glBegin %gl_triangle_strip
              glcolor3ub 255,120,120 : glvertex3f   -1, 3, -2     'vertex1
              glcolor3ub 255,0,0 : glvertex3f   2, 2, 2     'vertex2
              glcolor3ub 0,0,255 : glvertex3f   -2, 2, -2     'vertex3
              glcolor3ub 255,0,255 : glvertex3f   2, 1, 2     'vertex4
              glcolor3ub 0,255,255 : glvertex3f   0, 1, -2     'vertex5
              glcolor3ub 255,0,255 : glvertex3f   2, 0, 2     'vertex6
              glEnd
           CASE 3
              glBegin %gl_quad_strip
              glcolor3ub 0,255,0   : glVertex2f  -2,-3
              glcolor3ub 0,255,255 : glVertex2f   2, -3
              glcolor3ub 255,0,0   : glVertex2f  -2, 0
              glcolor3ub 0,255,255 : glVertex2f   2, 0
              glcolor3ub 255,255,0 : glVertex2f  -3, 3
              glcolor3ub 0,255,0   : glVertex2f   1, 1
              glcolor3ub 255,0,0   : glVertex2f  -4, 3
              glcolor3ub 0,255,255 : glVertex2f  -2, 3
              glEnd
         END SELECT
         SwapBuffers hDC              'display the buffer (image)
    END SUB
    '---------------------------------------------------------------------'
    SUB Readmodel
        LOCAL i1(),i2(),i3() AS SINGLE
        LOCAL inputfile$,dummy$,l$,i&,nr&
        LOCAL ax,ay,az,bx,by,bz,sq  AS SINGLE
         REDIM x(40000),y(40000),z(40000)      'vertex coordinates
        REDIM f(80000,3),fn(80000,3)          'faces and normals
         inputfile$="ESA_Rosetta_OSIRIS_67P_SHAP2P.obj"
        'Inputfile is the .obj file : http://sci.esa.int/rosetta/54728-sha...-of-comet-67p/
        vertices&=0:faces&=0:i&=0
        OPEN inputfile$ FOR INPUT AS #1
            WHILE ISFALSE EOF(#1)
            i&=i&+1
            'Format of Input : lists of vertices and faces
            'v 0.183863 -0.251854 -0.337678
            'f 14327 6959 18747
            LINE INPUT #1,dummy$
            l$=LEFT$(dummy$,1)
            IF l$="v" THEN
                vertices&=vertices&+1
                x(vertices&)=VAL (PARSE$(dummy$ , ANY " ", 2))
                y(vertices&)=VAL (PARSE$(dummy$ , ANY " ", 3))
                z(vertices&)=VAL (PARSE$(dummy$ , ANY " ", 4))
                END IF
            IF l$="f" THEN
                faces&=faces&+1
                f(faces&,1)=VAL (PARSE$(dummy$ , ANY " ", 2))
                f(faces&,2)=VAL (PARSE$(dummy$ , ANY " ", 3))
                f(faces&,3)=VAL (PARSE$(dummy$ , ANY " ", 4))
                END IF
            WEND
        CLOSE #1
        'calculating normals according to this formula
            'a.x = p2.x - p1.x;
            'a.y = p2.y - p1.y;
            'a.z = p2.z - p1.z;
             'b.x = p3.x - p1.x;
            'b.y = p3.y - p1.y;
            'b.z = p3.z - p1.z;
             'n.x = (a.y * b.z) - (a.z * b.y);
            'n.y = (a.z * b.x) - (a.x * b.z);
            'n.z = (a.x * b.y) - (a.y * b.x);
             '// Normalize (divide by root of dot product)
            'l = sqrt(n.x * n.x + n.y * n.y + n.z * n.z);
            'n.x /= l;
            'n.y /= l;
            'n.z /= l;
        FOR i&=1 TO faces&
            ax= x(f(i&,2))-x(f(i&,1))
            ay= y(f(i&,2))-y(f(i&,1))
            az= z(f(i&,2))-z(f(i&,1))
            bx= x(f(i&,3))-x(f(i&,1))
            by= y(f(i&,3))-y(f(i&,1))
            bz= z(f(i&,3))-z(f(i&,1))
            fn(i&,1)= (ay*bz)-(az*by)
            fn(i&,2)= (az*bx)-(ax*bz)
            fn(i&,3)= (ax*by)-(ay*bx)
            sq=SQR((fn(i&,1))^2+(fn(i&,2))^2+(fn(i&,3))^2)
            fn(i&,1)=fn(i&,1)/sq
            fn(i&,2)=fn(i&,2)/sq
            fn(i&,3)=fn(i&,3)/sq
        NEXT i&
     END SUB
    '---------------------------------------------------------------------'
    'fk derived from gbs_00586
    'Date: 03-10-2012
    As this is my first OpenGl code I must say I was positively surprised about the speed of rendering of this OpenGl mesh .
    I was doubtful when I saw the object file having 32k points and 80k faces .
    Last edited by Frank Kestens; 8 Apr 2015, 11:47 AM.

  • #2
    Hey Frank,
    Way cool! Not just the image but the code as well. Thanks for posting it!

    Here's the bas, exe and obj file in a single zip.

    Comment


    • #3
      ... with texture ...

      Hi Gary !
      Thanks ! First for providing your code gbs_00586 , second for promptly providing the zip file and the executable !

      I got inspired by this amazing work of Mathias Malmer here :
      http://mattias.malmer.nu/2015/03/360...r-joel-parker/

      I would like to add an appropriate texture to the comet in order to make the visualisation looking more realistic .
      Two hurdles to take :

      1. RTFM(s) concerning texture coding . Have to look here ...or elsewhere...
      ( any help is welcome )
      2. Find an appropriate texture . I've the impression that a lot of texture formats exists as an output of 3D generating software ...

      Edit :
      I saw Mr Mathias Malmer released an updated .obj mesh file , having 150.000 ! points and 300.000! triangles .
      The format of the new file required some adjustments for proper reading the file , but the sim runs as smooth as the above file . Even as it needs 62 MB of processor memory . Still , and even more impressed by OpenGl's power in PBWin .
      Last edited by Frank Kestens; 8 Apr 2015, 04:19 PM.

      Comment


      • #4
        ...some &quot;texture&quot; added ....

        Scientifically surely not correct , but acceptable for a human eye .
        I added hereunder in the code a kind of texture ( color per face) giving the illusion of texture in the comet .
        The color used is some expression which is function of the local slope on the comet .

        Code:
         ' fk 67P Comet OpenGL example   07/04/2015
        ' Revision 09/04/2015 : added a kind of random color per face in order to simulate some texture
        ' This code was derived from Gary Beenes' : gbs_00586 code Date: 03-10-2012
        ' I added the Comet option , which reads a data file holding the comets 67P mesh
        ' This file is  the .obj file which can be found here : http://sci.esa.int/rosetta/54728-sha...-of-comet-67p/
        ' Just save the file as it comes
         #COMPILER PBWIN 9, PBWIN 10
        #COMPILE EXE
        #DIM ALL
        #INCLUDE "win32api.inc"
        #INCLUDE "gl.inc"
        #INCLUDE "glu.inc"
         %ID_Timer = 1001 : %ID_Label = 1002
         GLOBAL hDlg, hDC, hRC, hLabel AS DWORD
        GLOBAL scalefactor AS SINGLE
        GLOBAL LightPosition(),LightPosition2() AS SINGLE
        GLOBAL x(),y(),z() AS SINGLE
        GLOBAL f(),coltex() AS LONG
        GLOBAL fn() AS SINGLE
        GLOBAL vertices&,faces&
         FUNCTION PBMAIN() AS LONG
            DIALOG NEW PIXELS, 0, "OpenGL Example 67P Comet",,, 500, 400,%WS_OVERLAPPEDWINDOW TO hDlg
            CONTROL ADD LABEL, hdlg, %ID_Label,"",110,10,100,100, %WS_CHILD OR %WS_VISIBLE OR %SS_SUNKEN OR %SS_NOTIFY
            CONTROL ADD OPTION, hdlg, 505,"Comet",10,110,100,20
            CONTROL ADD OPTION, hdlg, 506,"Triangle_Strip",10,130,100,20
            CONTROL ADD OPTION, hdlg, 507,"Quads",10,150,100,20
            CONTROL SET OPTION  hDlg, 505, 506, 507
            DIALOG SHOW MODAL hdlg CALL dlgproc
        END FUNCTION
        '---------------------------------------------------------------------'
        CALLBACK FUNCTION dlgproc()
            LOCAL pt AS POINT
            LOCAL XDelta, YDelta AS SINGLE
            STATIC SpinInWork,XLast,YLast AS LONG
             SELECT CASE CB.MSG
               CASE %WM_INITDIALOG : GetRenderContext
                  InitializeScene
                  SetTimer(hDlg, %ID_Timer, 50, %NULL)
                  ScaleFactor = 1
                  Readmodel
               CASE %WM_COMMAND    : IF CB.CTL > 504 AND CB.CTL < 508 THEN DrawScene 0,0,0
               CASE %WM_TIMER      : DrawScene 0,0.5,0  'redraw with rotation on y-axis
               CASE %WM_PAINT      : DrawScene 0,0,0  'redraw with no rotation
               CASE %WM_SIZE       : CONTROL SET SIZE hDlg, %ID_Label, LO(WORD, CB.LPARAM)-120, HI(WORD, CB.LPARAM)-20
                  ResizeScene LO(WORD, CB.LPARAM)-120, HI(WORD, CB.LPARAM)-20
                  DrawScene 0,0,0  'redraw with no rotation
               CASE %WM_CLOSE      : wglmakecurrent %null, %null 'unselect rendering context
                  wgldeletecontext hRC        'delete the rendering context
                  releasedc hDlg, hDC         'release device context
               CASE %WM_MOUSEWHEEL
                  SELECT CASE HI(INTEGER,CB.WPARAM)
                     CASE > 0  : ScaleFactor = ScaleFactor + 0.1 : DrawScene 0,0,0
                     CASE < 0  : ScaleFactor = ScaleFactor - 0.1 : DrawScene 0,0,0
                  END SELECT
               CASE %WM_SetCursor
                  GetCursorPos pt          'p.x and p.y are in screen coordinates
                  ScreenToClient hDlg, pt  'p.x and p.y are now dialog client coordinates
                  IF GetDlgCtrlID(ChildWindowFromPoint( hDlg, pt )) <> %ID_Label THEN EXIT FUNCTION
                  SELECT CASE HI(WORD, CB.LPARAM)
                     CASE %WM_LBUTTONDOWN
                        GetCursorPos pt              'pt has xy screen coordinates
                        ScreenToClient hDlg, pt       'pt now has dialog client coordinates
                        IF pt.y < 0 THEN EXIT SELECT
                        KillTimer CB.HNDL, %ID_Timer
                        SpinInWork = 1
                        XLast = Pt.x
                        YLast = Pt.y
                     CASE %WM_MOUSEMOVE
                        IF SpinInWork THEN
                           GetCursorPos pt           'pt has xy screen coordinates
                           ScreenToClient hDlg, pt    'pt now has dialog client coordinates
                           IF pt.y < 0 THEN EXIT SELECT
                           XDelta = XLast - Pt.x
                           YDelta = YLast - Pt.y
                           DrawScene -YDelta, -XDelta, 0
                           XLast = pt.x
                           YLast = pt.y
                        END IF
                     CASE %WM_LBUTTONUP
                        SpinInWork = 0
                        SetTimer(hDlg, %ID_Timer, 50, %NULL)
                  END SELECT
            END SELECT
        END FUNCTION
        '---------------------------------------------------------------------'
        SUB GetRenderContext
            LOCAL pfd AS PIXELFORMATDESCRIPTOR   'pixel format properties for device context
            pfd.nSize       =  SIZEOF(PIXELFORMATDESCRIPTOR)
            pfd.nVersion    =  1
            pfd.dwFlags     = %pfd_draw_to_window OR %pfd_support_opengl OR %pfd_doublebuffer
            pfd.dwlayermask = %pfd_main_plane
            pfd.iPixelType  = %pfd_type_rgba
            pfd.ccolorbits  = 24
            pfd.cdepthbits  = 24
             CONTROL HANDLE hdlg, %ID_Label TO hLabel
            hDC = GetDC(hLabel)
            SetPixelFormat(hDC, ChoosePixelFormat(hDC, pfd), pfd)  'set properties of device context
            hRC = wglCreateContext (hDC)                           'get rendering context
            wglMakeCurrent hDC, hRC                                'make the RC current
        END SUB
        '---------------------------------------------------------------------'
        SUB InitializeScene
            glClearColor 0,0,0,0     'sets color to be used with glClear
            glClearDepth 1           'sets zvalue to be used with glClear
            DIM LightDiffuse(3) AS SINGLE:  ARRAY ASSIGN LightDiffuse()  = 0.3, 0.3, 0.3, 1.0
            DIM LightAmbient(3) AS SINGLE:  ARRAY ASSIGN LightAmbient()  = 0.8, 0.8, 0.8, 1.0
            DIM LightPosition(3) AS SINGLE: ARRAY ASSIGN LightPosition() = 5.0, 5.0, 5.0, 1.0
            'CALL glLightfv(%GL_LIGHT0, %GL_DIFFUSE, LightDiffuse(0))     ' Setup The Diffuse Light
            CALL glLightfv(%GL_LIGHT0, %GL_Ambient, LightAmbient(0))     ' Setup The Ambient Light
            CALL glLightfv(%GL_LIGHT0, %GL_POSITION,  LightPosition(0))  ' Position The Light
            CALL glEnable(%GL_LIGHT0)                                    ' Enable Light Zero
            CALL glEnable(%GL_LIGHTING)                                  ' Enable Lighting
            CALL glEnable(%GL_COLOR_MATERIAL)                            ' Enable Coloring Of Material
            CALL glColorMaterial(%GL_FRONT AND %GL_BACK, %GL_AMBIENT_AND_DIFFUSE)
             glDepthFunc %gl_less                                'specify how depth-buffer comparisons are made
            glEnable %gl_depth_test                             'enable depth testing
            glShadeModel %gl_nicest '%gl_smooth                 'smooth shading or nicest
            glHint %gl_perspective_correction_hint, %gl_nicest  'best quality rendering
        END SUB
        '---------------------------------------------------------------------'
        SUB ResizeScene (w AS LONG, h AS LONG)
            glViewport 0, 0, w, h             'resize viewport to match window size
            glMatrixMode %gl_projection       'select the projection matrix
            glLoadIdentity                    'reset the projection matrix
            gluPerspective 45, w/h, 0.1, 100  'calculate the aspect ratio of the Window
            glMatrixMode %gl_modelview        'select the modelview matrix
        END SUB
        '---------------------------------------------------------------------'
        SUB DrawScene (dx AS SINGLE, dy AS SINGLE, dz AS SINGLE)
            STATIC anglex, angley, anglez AS SINGLE
            LOCAL i,j,k,r AS LONG
            FOR i = 1 TO 3
               CONTROL GET CHECK hDlg, 504+i TO j
               IF j = %True THEN EXIT FOR
            NEXT i
             glClear %gl_color_buffer_bit OR %gl_depth_buffer_bit  'clear buffers
            glLoadIdentity               'clear the modelview matrix
            gluLookAt 0,0,10,0,0,0,0,1,0
             glScalef scalefactor, scalefactor, scalefactor
             anglex = anglex + dx : glRotatef anglex, 1,0,0
            angley = angley + dy : glRotatef angley, 0,1,0
            anglez = anglez + dz : glRotatef anglez, 0,0,1
             SELECT CASE i
               CASE 1
                  FOR k=1 TO faces&
                  glBegin %gl_triangles
                  glcolor3ub coltex(k),coltex(k),coltex(k)                        'almost white color , added some red
                  glNormal3f(fn(k,1),fn(k,3),fn(k,3))           'normals in order to allow shading effects
                  glvertex3f  x(f(k,1)),y(f(k,1)),z(f(k,1))     'vertex1
                  glvertex3f  x(f(k,2)),y(f(k,2)),z(f(k,2))     'vertex2
                  glvertex3f  x(f(k,3)),y(f(k,3)),z(f(k,3))    'vertex3
                  glEnd
                  NEXT k
               CASE 2
                  glBegin %gl_triangle_strip
                  glcolor3ub 255,120,120 : glvertex3f   -1, 3, -2     'vertex1
                  glcolor3ub 255,0,0 : glvertex3f   2, 2, 2     'vertex2
                  glcolor3ub 0,0,255 : glvertex3f   -2, 2, -2     'vertex3
                  glcolor3ub 255,0,255 : glvertex3f   2, 1, 2     'vertex4
                  glcolor3ub 0,255,255 : glvertex3f   0, 1, -2     'vertex5
                  glcolor3ub 255,0,255 : glvertex3f   2, 0, 2     'vertex6
                  glEnd
               CASE 3
                  glBegin %gl_quad_strip
                  glcolor3ub 0,255,0   : glVertex2f  -2,-3
                  glcolor3ub 0,255,255 : glVertex2f   2, -3
                  glcolor3ub 255,0,0   : glVertex2f  -2, 0
                  glcolor3ub 0,255,255 : glVertex2f   2, 0
                  glcolor3ub 255,255,0 : glVertex2f  -3, 3
                  glcolor3ub 0,255,0   : glVertex2f   1, 1
                  glcolor3ub 255,0,0   : glVertex2f  -4, 3
                  glcolor3ub 0,255,255 : glVertex2f  -2, 3
                  glEnd
             END SELECT
             SwapBuffers hDC              'display the buffer (image)
        END SUB
        '---------------------------------------------------------------------'
        SUB Readmodel
            LOCAL inputfile$,dummy$,l$,i&,nr&
            LOCAL ax,ay,az,bx,by,bz,sq,rcent  AS SINGLE
             REDIM x(40000),y(40000),z(40000)      'vertex coordinates
            REDIM f(80000,3),fn(80000,3)          'faces and normals
            REDIM coltex(80000)                   'colored texture
             inputfile$="ESA_Rosetta_OSIRIS_67P_SHAP2P.obj"
            'Inputfile is the .obj file : http://sci.esa.int/rosetta/54728-sha...-of-comet-67p/
            vertices&=0:faces&=0:i&=0
            OPEN inputfile$ FOR INPUT AS #1
                WHILE ISFALSE EOF(#1)
                i&=i&+1
                'Format of Input : lists of vertices and faces
                'v 0.183863 -0.251854 -0.337678
                'f 14327 6959 18747
                LINE INPUT #1,dummy$
                l$=LEFT$(dummy$,1)
                IF l$="v" THEN
                    vertices&=vertices&+1
                    x(vertices&)=VAL (PARSE$(dummy$ , ANY " ", 2))
                    y(vertices&)=VAL (PARSE$(dummy$ , ANY " ", 3))
                    z(vertices&)=VAL (PARSE$(dummy$ , ANY " ", 4))
                    END IF
                IF l$="f" THEN
                    faces&=faces&+1
                    f(faces&,1)=VAL (PARSE$(dummy$ , ANY " ", 2))
                    f(faces&,2)=VAL (PARSE$(dummy$ , ANY " ", 3))
                    f(faces&,3)=VAL (PARSE$(dummy$ , ANY " ", 4))
                    END IF
                WEND
            CLOSE #1
            'calculating normals according to this formula
                'a.x = p2.x - p1.x;
                'a.y = p2.y - p1.y;
                'a.z = p2.z - p1.z;
                 'b.x = p3.x - p1.x;
                'b.y = p3.y - p1.y;
                'b.z = p3.z - p1.z;
                 'n.x = (a.y * b.z) - (a.z * b.y);
                'n.y = (a.z * b.x) - (a.x * b.z);
                'n.z = (a.x * b.y) - (a.y * b.x);
                 '// Normalize (divide by root of dot product)
                'l = sqrt(n.x * n.x + n.y * n.y + n.z * n.z);
                'n.x /= l;
                'n.y /= l;
                'n.z /= l;
            FOR i&=1 TO faces&
                ax= x(f(i&,2))-x(f(i&,1))
                ay= y(f(i&,2))-y(f(i&,1))
                az= z(f(i&,2))-z(f(i&,1))
                bx= x(f(i&,3))-x(f(i&,1))
                by= y(f(i&,3))-y(f(i&,1))
                bz= z(f(i&,3))-z(f(i&,1))
                fn(i&,1)= (ay*bz)-(az*by)
                fn(i&,2)= (az*bx)-(ax*bz)
                fn(i&,3)= (ax*by)-(ay*bx)
                sq=SQR((fn(i&,1))^2+(fn(i&,2))^2+(fn(i&,3))^2)
                fn(i&,1)=fn(i&,1)/sq
                fn(i&,2)=fn(i&,2)/sq
                fn(i&,3)=fn(i&,3)/sq
            NEXT i&
             'Generating sort of random color (texture) related to the normal of the local surface
            FOR i&=1 TO faces&
                coltex(i&) =100-50*(ABS(fn(i&,1)+fn(i&,2))-(fn(i&,3)))
            NEXT i&
        END SUB
        '---------------------------------------------------------------------'
        'fk derived from gbs_00586 Date: 03-10-2012

        Comment


        • #5
          Thanks, Frank, for the update. The new one is way easier on the eye!

          Both versions - bas, exe, obj - here.

          Comment


          • #6
            ...extension with second detailled shape model

            Code hereunder is an update of previous code .
            Features :
            1. The code lets one choose between two models of the 67P shape I've found on the internet .
            I added the
            67P_C-G_shapemodel_Malmer_2015_02_03.obj which can be found here :http://mattias.malmer.nu/category/rosetta/
            This model is far more detailed than the previous model and gives far better resolution (*)
            2. Added the option to toggle between light sources ( diffuse , ambient ,both ) . The combination of both light sources seems to give the best results

            (*) I would greatly appreciate if Gary could provide this new files in his folder

            Code:
             ' fk 67P Comet OpenGL example   07/04/2015
            ' Revision 09/04/2015 : added a kind of random color per face in order to simulate some texture
            ' Revision 10/04/2015 :
                                    'Added the facility to make selection of TWO possible shape maps I currently can find on the web
                                    'Added the facility of choosing light sources
                                    
            ' This code was derived from Gary Beenes' : gbs_00586 code Date: 03-10-2012
            ' T added the Comet option , which reads a data file holding the comets 67P mesh
            ' The first file is the .obj file which can be found here :  http://sci.esa.int/rosetta/54728-sha...-of-comet-67p/
            ' The second is the .obj file :http://mattias.malmer.nu/category/rosetta/
            ' Just save the file as it comes
             ' Note : as both .obj files don't provide a texture I had to apply some face color to each face
            ' I've choosen the color (texture illusion ) being a function of the local slope
             #COMPILER PBWIN 9, PBWIN 10
            #COMPILE EXE
            #DIM ALL
            #INCLUDE "win32api.inc"
            #INCLUDE "gl.inc"
            #INCLUDE "glu.inc"
             %ID_Timer = 1001 : %ID_Label = 1002
             GLOBAL hDlg, hDC, hRC, hLabel AS DWORD
            GLOBAL scalefactor AS SINGLE
            GLOBAL LightPosition(),LightPosition2() AS SINGLE
            GLOBAL x(),y(),z() AS SINGLE
            GLOBAL f(),coltex() AS LONG
            GLOBAL fn() AS SINGLE
            GLOBAL vertices&,faces&
             FUNCTION PBMAIN() AS LONG
                DIALOG NEW PIXELS, 0, "OpenGL Example 67P Comet",,, 500, 400,%WS_OVERLAPPEDWINDOW TO hDlg
                CONTROL ADD LABEL, hdlg, %ID_Label,"",110,10,100,100, %WS_CHILD OR %WS_VISIBLE OR %SS_SUNKEN OR %SS_NOTIFY
                CONTROL ADD OPTION, hdlg, 505,"Diffuse Light",10,110,100,20
                CONTROL ADD OPTION, hdlg, 506,"Ambient Light",10,130,100,20
                CONTROL ADD OPTION, hdlg, 507,"Diff + Ambient Light",10,150,100,20
                CONTROL SET OPTION  hDlg, 505, 506, 507
                DIALOG SHOW MODAL hdlg CALL dlgproc
            END FUNCTION
            '---------------------------------------------------------------------'
            CALLBACK FUNCTION dlgproc()
                LOCAL pt AS POINT
                LOCAL XDelta, YDelta AS SINGLE
                STATIC SpinInWork,XLast,YLast AS LONG
                 SELECT CASE CB.MSG
                   CASE %WM_INITDIALOG : GetRenderContext
                      InitializeScene
                      SetTimer(hDlg, %ID_Timer, 50, %NULL)
                      ScaleFactor = 1
                      Readmodel
                   CASE %WM_COMMAND    : IF CB.CTL > 504 AND CB.CTL < 506 THEN DrawScene 0,0,0
                   CASE %WM_TIMER      : DrawScene 0,0.5,0 'redraw with rotation on y-axiss
                   CASE %WM_PAINT      : DrawScene 0,0,0  'redraw with no rotation
                   CASE %WM_SIZE       : CONTROL SET SIZE hDlg, %ID_Label, LO(WORD, CB.LPARAM)-120, HI(WORD, CB.LPARAM)-20
                      ResizeScene LO(WORD, CB.LPARAM)-120, HI(WORD, CB.LPARAM)-20
                      DrawScene 0,0,0  'redraw with no rotation
                   CASE %WM_CLOSE      : wglmakecurrent %null, %null 'unselect rendering context
                      wgldeletecontext hRC        'delete the rendering context
                      releasedc hDlg, hDC         'release device context
                   CASE %WM_MOUSEWHEEL
                      SELECT CASE HI(INTEGER,CB.WPARAM)
                         CASE > 0  : ScaleFactor = ScaleFactor + 0.1 : DrawScene 0,0,0
                         CASE < 0  : ScaleFactor = ScaleFactor - 0.1 : DrawScene 0,0,0
                      END SELECT
                   CASE %WM_SetCursor
                      GetCursorPos pt          'p.x and p.y are in screen coordinates
                      ScreenToClient hDlg, pt  'p.x and p.y are now dialog client coordinates
                      IF GetDlgCtrlID(ChildWindowFromPoint( hDlg, pt )) <> %ID_Label THEN EXIT FUNCTION
                      SELECT CASE HI(WORD, CB.LPARAM)
                         CASE %WM_LBUTTONDOWN
                            GetCursorPos pt              'pt has xy screen coordinates
                            ScreenToClient hDlg, pt       'pt now has dialog client coordinates
                            IF pt.y < 0 THEN EXIT SELECT
                            KillTimer CB.HNDL, %ID_Timer
                            SpinInWork = 1
                            XLast = Pt.x
                            YLast = Pt.y
                         CASE %WM_MOUSEMOVE
                            IF SpinInWork THEN
                               GetCursorPos pt           'pt has xy screen coordinates
                               ScreenToClient hDlg, pt    'pt now has dialog client coordinates
                               IF pt.y < 0 THEN EXIT SELECT
                               XDelta = XLast - Pt.x
                               YDelta = YLast - Pt.y
                               DrawScene -YDelta, -XDelta, 0
                               XLast = pt.x
                               YLast = pt.y
                            END IF
                         CASE %WM_LBUTTONUP
                            SpinInWork = 0
                            SetTimer(hDlg, %ID_Timer, 50, %NULL)
                      END SELECT
                END SELECT
            END FUNCTION
            '---------------------------------------------------------------------'
            SUB GetRenderContext
                LOCAL pfd AS PIXELFORMATDESCRIPTOR   'pixel format properties for device context
                pfd.nSize       =  SIZEOF(PIXELFORMATDESCRIPTOR)
                pfd.nVersion    =  1
                pfd.dwFlags     = %pfd_draw_to_window OR %pfd_support_opengl OR %pfd_doublebuffer
                pfd.dwlayermask = %pfd_main_plane
                pfd.iPixelType  = %pfd_type_rgba
                pfd.ccolorbits  = 24
                pfd.cdepthbits  = 24
                 CONTROL HANDLE hdlg, %ID_Label TO hLabel
                hDC = GetDC(hLabel)
                SetPixelFormat(hDC, ChoosePixelFormat(hDC, pfd), pfd)  'set properties of device context
                hRC = wglCreateContext (hDC)                           'get rendering context
                wglMakeCurrent hDC, hRC                                'make the RC current
            END SUB
            '---------------------------------------------------------------------'
            SUB InitializeScene
                glClearColor 0,0,0,0     'sets color to be used with glClear
                glClearDepth 1           'sets zvalue to be used with glClear
                DIM LightDiffuse(3) AS SINGLE:  ARRAY ASSIGN LightDiffuse()  = 1.0, 0.9, 0.9, 1.0
                DIM LightAmbient(3) AS SINGLE:  ARRAY ASSIGN LightAmbient()  = 0.3, 0.3, 0.3, 1.0
                DIM LightPosition(3) AS SINGLE: ARRAY ASSIGN LightPosition() = 5.0, 5.0, 5.0, 1.0
                CALL glLightfv(%GL_LIGHT0, %GL_DIFFUSE, LightDiffuse(0))     ' Setup The Diffuse Light
                CALL glLightfv(%GL_LIGHT0, %GL_POSITION,  LightPosition(0))  ' Position The Light
                CALL glLightfv(%GL_LIGHT1, %GL_Ambient, LightAmbient(0))     ' Setup The Ambient Light
                CALL glEnable(%GL_LIGHT0)                                    ' Enable Light Zero
                CALL glEnable(%GL_LIGHT1)                                    ' Enable Light One
                CALL glEnable(%GL_LIGHTING)                                  ' Enable Lighting
                CALL glEnable(%GL_COLOR_MATERIAL)                            ' Enable Coloring Of Material
                CALL glColorMaterial(%GL_FRONT AND %GL_BACK, %GL_AMBIENT_AND_DIFFUSE)
                 glDepthFunc %gl_less                                'specify how depth-buffer comparisons are made
                glEnable %gl_depth_test                             'enable depth testing
                glShadeModel %gl_nicest '%gl_smooth                 'smooth shading or nicest
                glHint %gl_perspective_correction_hint, %gl_nicest  'best quality rendering
            END SUB
            '---------------------------------------------------------------------'
            SUB ResizeScene (w AS LONG, h AS LONG)
                glViewport 0, 0, w, h             'resize viewport to match window size
                glMatrixMode %gl_projection       'select the projection matrix
                glLoadIdentity                    'reset the projection matrix
                gluPerspective 45, w/h, 0.1, 100  'calculate the aspect ratio of the Window
                glMatrixMode %gl_modelview        'select the modelview matrix
            END SUB
            '---------------------------------------------------------------------'
            SUB DrawScene (dx AS SINGLE, dy AS SINGLE, dz AS SINGLE)
                STATIC anglex, angley, anglez AS SINGLE
                LOCAL i,j,k  AS LONG
                FOR i = 1 TO 3
                   CONTROL GET CHECK hDlg, 504+i TO j
                   IF j = %True THEN EXIT FOR
                NEXT i
                 glClear %gl_color_buffer_bit OR %gl_depth_buffer_bit  'clear buffers
                glLoadIdentity                                        'clear the modelview matrix
                gluLookAt 0,0,10,0,0,0,0,1,0
                 glScalef scalefactor, scalefactor, scalefactor
                 anglex = anglex + dx : glRotatef anglex, 1,0,0
                angley = angley + dy : glRotatef angley, 0,1,0
                anglez = anglez + dz : glRotatef anglez, 0,0,1
                 SELECT CASE i
                CASE 1
                   CALL glEnable(%GL_LIGHT0)                                    ' Enable Light Zero
                   CALL glDisable(%GL_LIGHT1)                                   ' Disable Light One
                   CALL glEnable(%GL_LIGHTING)                                  ' Enable Lighting
                CASE 2
                   CALL glEnable(%GL_LIGHT1)                                    ' Enable Light One
                   CALL glDisable(%GL_LIGHT0)                                   ' Disable Light Zero
                   CALL glEnable(%GL_LIGHTING)
                CASE 3
                   CALL glEnable(%GL_LIGHT1)                                    ' Enable Light One
                   CALL glEnable(%GL_LIGHT0)                                    ' Enable Light Zero
                   CALL glEnable(%GL_LIGHTING)
                END SELECT
                 FOR k=1 TO faces&                                   'here the "drawing" is done
                      glBegin %gl_triangles
                      glcolor3ub coltex(k),coltex(k),coltex(k)      '"false" colors
                      glNormal3f(fn(k,1),fn(k,3),fn(k,3))           'normals in order to allow shading effects
                      glvertex3f  x(f(k,1)),y(f(k,1)),z(f(k,1))     'vertex1
                      glvertex3f  x(f(k,2)),y(f(k,2)),z(f(k,2))     'vertex2
                      glvertex3f  x(f(k,3)),y(f(k,3)),z(f(k,3))    'vertex3
                      glEnd
                 NEXT k
                 SwapBuffers hDC              'display the buffer (image)
            END SUB
            '---------------------------------------------------------------------'
            SUB Readmodel                               'select file , open , read and convert to coordinates, faces, texture
                LOCAL inputfile$,dummy$,l$,ll$
                LOCAL i&,nr&
                LOCAL ax,ay,az,bx,by,bz,sq  AS SINGLE
                LOCAL maxx                  AS SINGLE
                 REDIM x(400000),y(400000),z(400000)     'vertex coordinates
                REDIM f(380000,3),fn(380000,3)          'faces and normals
                REDIM coltex(380000)                    'colored texture
                'Two possible inputfiles are coded to open
                'inputfile$="ESA_Rosetta_OSIRIS_67P_SHAP2P.obj"
                    'Inputfile is the .obj file : http://sci.esa.int/rosetta/54728-sha...-of-comet-67p/
                'inputfile$="67P_C-G_shapemodel_Malmer_2015_02_03.obj"
                    'Inputfile is the .obj file :http://mattias.malmer.nu/category/rosetta/
                'Both inputfiles need special attention !
                DISPLAY OPENFILE 0, 100, 30, "Select the .obj  file ", _
                        "", CHR$("obj", 0, "*.obj", 0), "", _
                        "", %OFN_FILEMUSTEXIST TO  inputfile$
                 vertices&=0:faces&=0
                IF INSTR(inputfile$,"Malmer")>0  THEN
                    OPEN inputfile$ FOR INPUT AS #1
                    WHILE ISFALSE EOF(#1)
                    'Format of Input : lists of vertices and faces
                    'v 0.183863 -0.251854 -0.337678
                    'f 14327 6959 18747
                    LINE INPUT #1,dummy$
                    l$=LEFT$(dummy$,1)
                    IF l$="v" THEN
                        vertices&=vertices&+1
                        ll$=CLIP$(LEFT  dummy$, 3)
                        x(vertices&)=VAL (PARSE$(ll$ , ANY " ", 1))
                        y(vertices&)=VAL (PARSE$(ll$ , ANY " ", 2))
                        z(vertices&)=VAL (PARSE$(ll$ , ANY " ", 3))
                        END IF
                    IF l$="f" THEN
                        faces&=faces&+1
                        f(faces&,1)=VAL (PARSE$(dummy$ , ANY " ", 2))
                        f(faces&,2)=VAL (PARSE$(dummy$ , ANY " ", 3))
                        f(faces&,3)=VAL (PARSE$(dummy$ , ANY " ", 4))
                        END IF
                    WEND
                    CLOSE #1
                END IF
                 IF INSTR(inputfile$,"Rosetta")>0  THEN
                    OPEN inputfile$ FOR INPUT AS #1
                    WHILE ISFALSE EOF(#1)
                    'Format of Input : lists of vertices and faces
                    'v 0.183863 -0.251854 -0.337678
                    'f 14327 6959 18747
                    LINE INPUT #1,dummy$
                    l$=LEFT$(dummy$,1)
                    IF l$="v" THEN
                        vertices&=vertices&+1
                        x(vertices&)=VAL (PARSE$(dummy$ , ANY " ", 2))
                        y(vertices&)=VAL (PARSE$(dummy$ , ANY " ", 3))
                        z(vertices&)=VAL (PARSE$(dummy$ , ANY " ", 4))
                        END IF
                    IF l$="f" THEN
                        faces&=faces&+1
                        f(faces&,1)=VAL (PARSE$(dummy$ , ANY " ", 2))
                        f(faces&,2)=VAL (PARSE$(dummy$ , ANY " ", 3))
                        f(faces&,3)=VAL (PARSE$(dummy$ , ANY " ", 4))
                        END IF
                    WEND
                    CLOSE #1
                END IF
                ' Do some scaling in x-direction
                FOR i&=1 TO vertices&
                    maxx=MAX(ABS(x(i&)),maxx)
                NEXT i&
                FOR i&=1 TO vertices&
                    x(i&)=x(i&)/maxx
                    y(i&)=y(i&)/maxx
                    z(i&)=z(i&)/maxx
                NEXT i&
                'calculating normals according to this formula  ( see : OpenGl Wiki )
                    'a.x = p2.x - p1.x;
                    'a.y = p2.y - p1.y;
                    'a.z = p2.z - p1.z;
                    'b.x = p3.x - p1.x;
                    'b.y = p3.y - p1.y;
                    'b.z = p3.z - p1.z;
                    'n.x = (a.y * b.z) - (a.z * b.y);
                    'n.y = (a.z * b.x) - (a.x * b.z);
                    'n.z = (a.x * b.y) - (a.y * b.x);
                    '// Normalize (divide by root of dot product)
                    'l = sqrt(n.x * n.x + n.y * n.y + n.z * n.z);
                    'n.x /= l;
                    'n.y /= l;
                    'n.z /= l;
                FOR i&=1 TO faces&
                    ax= x(f(i&,2))-x(f(i&,1))
                    ay= y(f(i&,2))-y(f(i&,1))
                    az= z(f(i&,2))-z(f(i&,1))
                    bx= x(f(i&,3))-x(f(i&,1))
                    by= y(f(i&,3))-y(f(i&,1))
                    bz= z(f(i&,3))-z(f(i&,1))
                    fn(i&,1)= (ay*bz)-(az*by)
                    fn(i&,2)= (az*bx)-(ax*bz)
                    fn(i&,3)= (ax*by)-(ay*bx)
                    sq=SQR((fn(i&,1))^2+(fn(i&,2))^2+(fn(i&,3))^2)
                    fn(i&,1)=fn(i&,1)/sq
                    fn(i&,2)=fn(i&,2)/sq
                    fn(i&,3)=fn(i&,3)/sq
                NEXT i&
                'Finally Generating sort of  color (false texture) related to the normal of the local surface
                FOR i&=1 TO faces&
                    coltex(i&) =200-50*(ABS(fn(i&,1)+fn(i&,2))-(fn(i&,3)))
                NEXT i&
            END SUB
            '---------------------------------------------------------------------'
            'fk derived from gbs_00586 Date: 03-10-2012
            Last edited by Frank Kestens; 10 Apr 2015, 02:52 PM.

            Comment


            • #7
              Done. All 3 versions in a zip file here.

              Comment


              • #8
                ...thanks ...

                Thanks Gary !
                Eventual users can download the file "67P_C-G_shapemodel_Malmer_2015_02_03.obj" here :http://mattias.malmer.nu/category/rosetta/ and use it .
                As far as I know this should be the best shape model of the comet as existing now.
                (unfortunately I couldn't find a matching texture model for it )
                Last edited by Frank Kestens; 10 Apr 2015, 04:58 PM.

                Comment


                • #9
                  Everything, with both OBJ files ... here. ~6MB download

                  Comment

                  Working...
                  X