Oxygen Basic

Information => Introducing Oxygen => Topic started by: Charles Pegge on October 01, 2010, 09:12:44 AM

Title: Screen Shots
Post by: Charles Pegge on October 01, 2010, 09:12:44 AM
Screen Shots

These are screen shots of OpenGL demos found in the Asm and GL example folder.

(http://www.oxygenbasic.org/o2pics/opengl/Opengl1.png)

(http://www.oxygenbasic.org/o2pics/opengl/Opengl2.png)
Title: Re: Screen Shots
Post by: Charles Pegge on October 19, 2010, 12:06:45 AM
Opengl with text


(http://www.oxygenbasic.org/o2pics/opengl/Alpha018.jpg)
Title: Re: Screen Shots
Post by: kryton9 on October 19, 2010, 02:11:18 AM
Good idea Charles, nice to see screenshots.
Title: Re: Screen Shots
Post by: Charles Pegge on October 24, 2010, 12:32:28 PM
Developing Text scroll:

(http://www.oxygenbasic.org/o2pics/opengl/Alpha019.jpg)
Title: Re: Screen Shots
Post by: efgee on October 25, 2010, 08:50:35 AM
Charles,
when I first read that you want to create an editor based on OpenGL I thought you were joking, but the last screenshot shows you are serious  :o

Everybody else is mostly using Scintilla or RAEdit, but you go for OpenGL. If you can pull it off adding cool editor functionality then AFAIK it's the first OpenGL source code editor... ever  8)

That's a lot of work ahead of you.

bye
efgee
Title: Re: Screen Shots
Post by: Charles Pegge on October 25, 2010, 02:59:42 PM
Compared to wrestling with Windows edit controls this is sheer bliss. Even though Opengl is full of surprises at every turn. The scrolling is now creamy smooth.

The start of syntax Highlighting. :)

Charles

(http://www.oxygenbasic.org/o2pics/opengl/Alpha019sh.jpg)
Title: Re: Screen Shots
Post by: kryton9 on October 27, 2010, 04:32:22 PM
Super job Charles. I hit a wall in my development and went off track trying to figure out an ideal data system to handle everything.
What are you using? Any STL type containers and algorithms?
Title: Re: Screen Shots
Post by: Charles Pegge on October 28, 2010, 02:31:49 PM

Hi Kent,

I'm not familiar with STL. This is coded from scratch. Up to this demo the code was straight procedural but I have reached the stage where further encapsulation is desirable and thus begins the process of collecting functions together into classes.

Not sure there is an ideal data system to fit all needs. For instance in low level data processing using SQL would be very inefficient and you would use hard coded data structures instead or hold the data in arrays of strings.

Charles
Title: Re: Screen Shots
Post by: Charles Pegge on November 03, 2010, 08:52:43 AM
Edit Control unhitched from the viewport, and now independently moveable and scalable.



(http://www.oxygenbasic.org/o2pics/opengl/Alpha019b.jpg)
Title: Re: Screen Shots
Post by: kryton9 on November 07, 2010, 01:12:57 PM
My internet has been down for over a week. I am writing short as it might cut off as it had been doing. This screenshot looks great, very exciting to see such an editor!
Title: Re: Screen Shots
Post by: Charles Pegge on November 07, 2010, 07:28:25 PM
Hi Kent. It could be mites in the file servers or alligators chewing the cables :) Better luck with your Internet this week!

I've made further progress in encapsulating the edit control. The font size and the box size can also be independently scaled. The edit boxes may overlap but further work needs to been done assigning separate layers and priorities.


(http://www.oxygenbasic.org/o2pics/opengl/Alpha019c.jpg)
Title: Re: Screen Shots
Post by: kryton9 on November 08, 2010, 06:14:37 PM
I'll be getting the latest version and playing this week. Lots to catch up on... which is awesome!!
Title: Re: Screen Shots
Post by: Charles Pegge on December 02, 2010, 10:08:57 PM

Gaussian distribution in 2 dimensions.



.
Title: Re: Screen Shots
Post by: Charles Pegge on December 03, 2010, 05:55:59 AM
Gaussian hump mixed with height noise:


(http://www.oxygenbasic.org/o2pics/opengl/Gauss2.jpg)
Title: Re: Screen Shots
Post by: kryton9 on December 03, 2010, 01:00:52 PM
Nice screenshots Charles, thanks.
Title: Re: Screen Shots
Post by: Charles Pegge on December 04, 2010, 02:32:49 PM
Gaussian hump with height noise and texture noise:



(http://www.oxygenbasic.org/o2pics/opengl/GaussTextured.jpg)
Title: Re: Screen Shots
Post by: Charles Pegge on December 08, 2010, 08:34:04 PM

Multiple Opengl child windows demo:
(you can edit the rotation speed for each window)






.
Title: Re: Screen Shots
Post by: kryton9 on December 09, 2010, 01:02:21 PM
Are these seperate windows or are they viewports Charles? Thanks for the update!
Title: Re: Screen Shots
Post by: Charles Pegge on December 09, 2010, 03:55:37 PM

These are individual windows Kent.

Each has their own graphics context (hDC) but they share the rendering context (hRC). Each is rendered separately on the WM_TIMER after context switching (wglMakeCurrent hDCn, hRC).

Sharing the same hRC ensures that defined lists, textures etc are shared. I remember Petr warning me some graphics cards have problems deploying more than one hRC.

Charles
Title: Re: Screen Shots
Post by: kryton9 on December 09, 2010, 09:16:56 PM
Thanks for the clarification Charles.
Title: Re: Screen Shots
Post by: Petr Schreiber on December 10, 2010, 01:20:52 AM
Hi Charles,

yes, some of the implementations of wglShareLists are perfect recipe for testing headache.
In following text: hRC = rendering contect, hDC = graphic context

Your solution "multiple hDC, single hRC" sounds great, but ... how did you managed that? The usual way to create hRC is something like:
Code: [Select]
hRC = wglCreateContext( hDC )

So if each window has its own hDC, how is it possible they can have the same hRC? :)


Petr
Title: Re: Screen Shots
Post by: Charles Pegge on December 10, 2010, 01:38:10 AM

Hi Petr,

This is what I did:

Code: [Select]

            '
            'SETUP DEVICE CONTEXTS FOR EACH OPENGL CHILD WINDOW
            '
            for i=3 to 4
              '
              chw=hw[i] 'get child handle
              hDC=GetDC chw
              hD[i]=hDC
              '
              PixelFormat(hDC,0)
              finit 'reinitialise fpu after npixelformat
              '
            next
            '
            'create only one render context for several device contexts
            hRC = wglCreateContext(hD[3])

The whole demo piece:  examples\gui\OpenglChildWins.o2bas

Charles

Title: Re: Screen Shots
Post by: Charles Pegge on December 10, 2010, 05:34:00 AM
I did some further tests to ensure the the Opengl Windows were truly independent in terms of viewport proportions and found there was no interference between them.

If the windows are of different size and shape then every time a window is rendered, the viewport and perspective must be respecified.

Charles

Code: [Select]
 '---------------------------
  sub PrepareRenderFor(sys n)
  '===========================
  {
    'GET CHILD HANDLE AND DEVICE CONTEXT FOR RENDERING
    '
    chw=hw[n] : hdc=hd[n]
    '
    wglMakeCurrent hDC, hRC
    '
    'SET THE VIEWPORT AND PERSPECTIVE
    '
    rect crect
    GetClientRect  chw,&cRect
    glViewport 0, 0, crect.right, crect.bottom
    double aspect=crect.right/crect.bottom
    '
    glMatrixMode   GL_PROJECTION
    glLoadIdentity
    gluPerspective 45, aspect, 1.0, 100
    glMatrixMode   GL_MODELVIEW
    glLoadIdentity
    '
    glClear GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT
  }

The example below should be placed in examples\gui


.
Title: Re: Screen Shots
Post by: Petr Schreiber on December 10, 2010, 06:40:19 AM
Thanks Charles,

now it makes sense. The side effect of this is that any state changes you do while rendering to first window (such as last color specified, blending enabled, ...) will immediately "bleed" to other windows as well, which is given by the fact single rendering context is used. If this is something you dislike, that is exactly the point where separate rendering contexts could come in, but it is problematic. At least on ATi hardware, no OpenGL error specified, but it corrupted graphics of any window I dragged over such a multitarget area on Windows 7.


Thanks,
Petr
Title: Re: Screen Shots
Post by: Charles Pegge on December 10, 2010, 09:02:13 AM
Yes exactly Petr, the entire scene has to be rebuilt from scratch and that includes setting the state variables. But sharing textures and compiled lists outweighs the disadvantages I think.

You can also be very selective with window refresh.

Charles
Title: Re: Screen Shots
Post by: Charles Pegge on December 14, 2010, 06:11:35 AM
More Geometry (Alpha023)



(http://www.oxygenbasic.org/o2pics/opengl/Helix1.jpg)




(http://www.oxygenbasic.org/o2pics/opengl/Geom2.jpg)
Title: Re: Screen Shots
Post by: kryton9 on December 14, 2010, 11:01:15 AM
Thanks for the updates Charles.
Title: Re: Screen Shots
Post by: Charles Pegge on December 15, 2010, 02:15:14 PM
Spirodome

The surface is made of flat diamond shaped panels. They all have the same length sides. Only the angles change.

This code demonstrates the spirodome geometry and will be included in the next release (>=alpha 024)

Code: [Select]
 '-----------------------------
  sub Spirodome(single h, sys n)
  '=============================
  '
  'n sides eg: 10
  'h height factor eg: .3
  '
  double a,b,r,x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4
  double a1,a2,a3,a4,r1,r2,r3,r4
  double na,nx,ny,nz
  double ha,rd,w1,w2,l1,l2,s1,s2,h1,h2
  '
  sys i,j,k,alt
  '
  'PRELIM CALCULATIONS
  '-------------------
  '
  a=2*pi()/n          'panel step angle
  ha=a*.5             'half angle
  r=1                 'initial radius
  if h<=0 then h=.001
  h1=h                'first panel height contribution
  w1=sin ha           'intial pael half width
  s1=sqr(w1*w1+h1*h1) 'panel side constant
  rd=0                'radius step difference
  a1=-ha              'initial face-on displacement
  ny=0                'normal y components
  y1=0
  y2=y1+h1
  '
  'EACH TIER
  '---------
  '
  for j=1 to 7
    '
    'EACH PANEL
    '----------
    '
    x1=r*sin a1
    z1=r*cos a1
    '
    for i=1 to n
      a2=a1+a
      x2=r*sin a2
      z2=r*cos a2
      '
      'face normal
      '
      nx=sin na
      nz=cos na
      '
      'BASE QUAD
      '---------
      '
      '
      if j=1 then
        glbegin GL_QUADS
        glNormal3f nx,ny,nz
        glVertex3f x1,y1,z1
        glVertex3f x2,y1,z2
        glVertex3f x2,y2,z2
        glVertex3f x1,y2,z1
        glend
      end if
      '
      '
      'TIP TRIANGLE
      '------------
      '
      r3=r*cos(ha) -rd
      a3=a1+ha
      x3=r3*sin a3
      y3=y2+h1
      z3=r3*cos a3
      '
      glbegin GL_TRIANGLES
      glNormal3f nx,ny,nz
      glVertex3f x1,y2,z1
      glVertex3f x2,y2,z2
      glVertex3f x3,y3,z3
      glend
      '
      'TAIL TRIANGLE
      '-------------
      '
      x4=r4*sin a3
      z4=r4*cos a3
      '
      if j>1 then
        glbegin GL_TRIANGLES
        glNormal3f nx,ny,nz
        glVertex3f x2,y2,z2
        glVertex3f x1,y2,z1
        glVertex3f x4,y4,z4
        glend
      end if
      '
      '
      'ANGLES FOR NEXT PANEL
      '
      a1=a2 : x1=x2 : z1=z2
      na=a1+ha 'angle for next normal
      '
    next
    '
    'next tier
    '---------
    '
    'CALCULATIONS FOR NEXT PANEL SET
    '-------------------------------
    '
    w1=r3*sin ha        'panel half width
    l1=sqr(s1*s1-w1*w1) 'panel half length
    rd=r-r3             'inward step
    h1=sqr(l1*l1-rd*rd) 'half height given by panel
    ny=rd/l1            'normal y component
                        '
    r4=r                'for tail coords
    y4=y2               'for tail coords
    r=r3                'update radius
    y1=y2
    y2=y3
    alt=1-alt 'alternate starting angle for next tier
    if alt then a1=0 else a1=-ha
    na=a1+ha
    '
  next
  '
  end sub


Charles


(http://www.oxygenbasic.org/o2pics/opengl/Spirodome10n.jpg)
Title: Re: Screen Shots
Post by: kryton9 on December 15, 2010, 05:32:57 PM
Will be a very helpful shape for making a hot air balloon in a game.

In other code Charles, I noticed you using macros instead of calling a sub. What is the reason for that?
I am guessing performance?
Title: Re: Screen Shots
Post by: Charles Pegge on December 15, 2010, 11:03:06 PM
Hi Kent,

In PortViewer2 I use macros mainly for convenience to bring selected parts of the code to the main program file. All the other bits like the Windows API remain out of site.

This is one way to implement Aspect-Oriented programming.
http://en.wikipedia.org/wiki/Aspect-oriented_programming

Charles
Title: Re: Screen Shots
Post by: kryton9 on December 16, 2010, 08:21:01 PM
Neat Charles, don't recall every hearing about this type of programming, but makes sense.
Title: Re: Screen Shots
Post by: Charles Pegge on December 22, 2010, 03:45:13 PM
Spirodome 2


(http://www.oxygenbasic.org/o2pics/opengl/Dome024.jpg)



Title: Re: Screen Shots
Post by: kryton9 on December 23, 2010, 10:56:52 AM
Again a very nice new shape and screenshot, thanks!
Title: Re: Screen Shots
Post by: Charles Pegge on March 26, 2011, 03:41:29 AM
Jpeg Images using GDIplus (examples/GUI/ImageWin.o2bas)

(http://www.oxygenbasic.org/o2pics/pixel/ImageWin.jpg)
Title: Re: Screen Shots
Post by: Charles Pegge on April 16, 2011, 07:20:19 AM
Jpeg background image texture using GDIplus (examples/GUI/PortViewer2.o2bas)

This screen has been posed :)  hint: F7,   4,  M+ArrowKeys

(http://www.oxygenbasic.org/o2pics/opengl/BackImg.jpg)
Title: Re: Screen Shots
Post by: kryton9 on April 20, 2011, 08:47:21 PM
Nice seeing the progress Charles, thanks.
Title: Re: Screen Shots
Post by: JRS on April 21, 2011, 10:25:09 PM
Wow!

It really runs well under Linux. I was using my mouse to move the image around and it was a instant reaction to every movement. AMAZING!
Title: Re: Screen Shots
Post by: Charles Pegge on May 01, 2011, 11:46:30 PM

Using examples/GUI/PortViewer2.o2bas

 F5 NumKey 7  ArrowKeys to move/rotate =/- to enlarge or reduce


(http://www.oxygenbasic.org/o2pics/opengl/Palace1.jpg)


F4 for wire frame orthogonal view

(http://www.oxygenbasic.org/o2pics/opengl/Palace1Wire.jpg)


PortViewer2 Controls
Code: [Select]
17:23 04/12/2010
Charles Pegge

DEMO:

Work in progress to develop Opengl Controls including text navigation,
editing, and to give OxygenBasic a thorough workout!

-------------
Viewing Modes
=============


  Function keys
  =============
  F1  (reserved for help)
  F4  Wire frame orthogonal view
  F5  Shaded 3d view
  F6  Four viewports combining orthogonal and perspective
  F7  Listing
  F8  Combined Listing with Perspective view of object
  F9  Reset position of object

  Other active keys:
  '-----------------

  Numeric keys: used for selecting demo objects
  1  Helical
  2  Torus Cylinder Composite
  3  Gaussian surface with noise
  4  Gaussian surface with noise and texture
  5  Faceted cone and cylinder
  6  Spirodome
  7  Palace Composite


  Space: toggles object rotation
  M +    speed up rotation
  M -    slow down rotation
  P      Take Jpeg Photo

  +      enlarge object
  -      reduce object
  left arrow   rotate y axis clockwise
  right arrow  rotate y axis anticlockwise
  up arrow     rotate x axis
  down arrow   rotate x axis
  Home         Move left
  End          Move right
  Pg Up        Move Up
  Pg Down      Move down

  When "M" key is held down:

  left arrow         Move left
  End          Move right
  Pg Up        Move Up
  Pg Down      Move down




  Mouse
  =====

  Moving with:

  Left Button Down   Rotate Object

  when 'M' key is also held down the Object can also be moved in X and Y directions




  '-------------
  List/Edit Mode
  '=============

  Scrolling zones:
  '---------------

  Using the mouse:

  UP    Top Left
  DOWN  Bottom Left

  When Left button is held down:

  Highlight select word and character

  Left button double click

  The selected word is highlighted and any other occurence of the character
  pattern is also highlighted throughout the listing.


  The Window may be freely resized

  Navigation keys:
  ----------------

  UP DOWN LEFT RIGHT
  PAGE-UP PAGE-DN HOME END
  CTRL-PG-GUP CTRL-PG DN

  F1 (reserved for help)
  F3: jump to next highlighted keyword.


Charles
Title: Re: Screen Shots
Post by: kryton9 on May 03, 2011, 04:44:58 PM
Thanks for the update Charles.

A quick question, what does this exactly do?
 $ GDIplus   
In the help it says it defines a constant, but what value is assigned to the constant when none is given?



Title: Re: Screen Shots
Post by: Charles Pegge on May 03, 2011, 07:32:19 PM
Hi Kent,

Macro or equate  would be more accurate. It is equivalent to '%'.

In this case, it is just a null entity which can be tested later: #ifdef GDIplus ...#endif

Charles
Title: Re: Screen Shots
Post by: Charles Pegge on May 03, 2011, 09:42:53 PM

Generating tower blocks:

(http://www.oxygenbasic.org/o2pics/opengl/TowerBlocks1.jpg)

Code: [Select]

  glNewList drawing_List 10, GL_COMPILE
  '====================================
  '
  '--------
  'BUILDING
  '========
  '
  glpushmatrix
  glbegin GL_QUADS
  '
  '
  'FRONT
  '
  glNormal3f  0,  0,  1
  glVertex3f -1,  0,  1
  glVertex3f -1,  2,  1
  glVertex3f  1,  2,  1
  glVertex3f  1,  0,  1
  '
  'RIGHT
  '
  glNormal3f  1,  0,  0
  glVertex3f  1,  0,  1
  glVertex3f  1,  2,  1
  glVertex3f  1,  2, -1
  glVertex3f  1,  0, -1
  '
  'BACK
  '
  glNormal3f  0,  0, -1
  glVertex3f  1,  0, -1
  glVertex3f  1,  2, -1
  glVertex3f -1,  2, -1
  glVertex3f -1,  0, -1
  '
  'LEFT
  '
  glNormal3f -1,  0,  0
  glVertex3f -1,  0, -1
  glVertex3f -1,  2, -1
  glVertex3f -1,  2,  1
  glVertex3f -1,  0,  1
  '
  'TOP
  '
  glNormal3f  0,  1,  0
  glVertex3f -1,  2,  1
  glVertex3f -1,  2, -1
  glVertex3f  1,  2, -1
  glVertex3f  1,  2,  1
  glend
  glpopmatrix
  glEndList



  glNewList drawing_List 11, GL_COMPILE
  '====================================
  '
  '------------
  'TOWER BLOCKS
  '============
  '
  single ma[10]<=(.15, .15, .2, 1.0,  .15, .15, .2, 1.0,   .0,  .0, .1, 1.0,  0)
  SetMaterial ma
  '
  'roadways ahead
  '
  for i=1 to 7
  glpushmatrix
  gltranslatef .8*i-1.2,0,0 '-3.5
  glscalef .1, .005, 4.0
  glCallList drawing_List 10 'building
  glpopmatrix
  next
  '
  'roadways across
  '
  for i=1 to 9
  glpushmatrix
  gltranslatef 2, 0, i*.8-3.3 '-6.8
  glscalef 3, .005, .1
  glCallList drawing_List 10 'building
  glpopmatrix
  next
  '
  'block of buildings
  '
  StandardMaterial
  '
  glTranslatef 0, 0, 3.5
  '
  for j=1 to 8
  for i=1 to 6
  partno i
  glpushmatrix
  glscalef .2+rnd()*.05, .5+rnd()*.2, .15+rnd()*.125
  glCallList drawing_List 10 'building
  glpopmatrix
  gltranslatef .8,0,0
  next
  gltranslatef -4.8,0,-.8
  next
  '
  glEndList


Charles
Title: Re: Screen Shots
Post by: kryton9 on May 04, 2011, 01:23:23 AM
That is cool. Getting into procedural stuff, I like it!!!
Title: Re: Screen Shots
Post by: Charles Pegge on May 05, 2011, 01:31:59 AM

Adding variety to the tower forms:

(http://www.oxygenbasic.org/o2pics/opengl/TowerBlocks2.jpg)
Title: Re: Screen Shots
Post by: Charles Pegge on September 08, 2011, 12:35:18 PM

Mace head used for attacking bugs!

(http://www.oxygenbasic.org/o2pics/opengl/Hex80PX.jpg)
Title: Re: Screen Shots
Post by: Peter on September 09, 2011, 06:21:09 AM
Hi Charles,

looks like a spike bomb.

Code: [Select]
IndexBase 0
Include "window.h"

SetWindow "Charles Spike Bomb",640,600,w_1
SetFont 12,24,0,"times"
SetColorKey 255,128,255
sys_mode=4

sys spike,x,z,fps
spike= LoadBmp "spiky/spike32.bmp",256,256

While WinExit=0
fps = ShowFrames()
cls 0x00FF00
SetBmp spike,50,10,512,512,z
z +=1
iF z >=32 Then z=0
SetText "Frames = " + fps,0,0,0x5F8BDC
DoEvents
SwapBuffers
WaitFrames 10
Wend

WinEnd
Title: Re: Screen Shots
Post by: Peter on September 09, 2011, 07:30:57 AM
another test  with new command  PAUSE.
hit any key quite short once.

Code: [Select]
indexbase 0
include "window.h"

SetWindow "Farbe",640,480,w_1
SetFont 22,44,0,""

SetText "Your grandfather",100,100,255
Pause
cls 0xFF0000
SetText "is still alive.",100,100,255
Pause
cls 0x00FF00
SetText "Bet your boots!",100,100,255
Pause

While sys_key=0
cls 0x00FFFF
SetText "Okay, hit key ",100,100,255

DoEvents
SwapBuffers
Wend

WinEnd
Title: Re: Screen Shots
Post by: Charles Pegge on September 10, 2011, 07:10:17 AM

The art of creating a geodesic structure is to ensure that all the panels and openings are flat. This requires some slightly tricky maths to resolve the position of each vertex, so that the flat panels fit together perfectly.

Oxygen (in progress version)
projects/3dview/PortViewer2.o2bas  [press '8' ]

(http://www.oxygenbasic.org/o2pics/opengl/Hex160PE.jpg)
Title: Re: Screen Shots
Post by: Peter on September 10, 2011, 10:08:13 AM
Hi Charles,

looks like an Easter egg!

this is more tricky.

Code: [Select]
indexbase 0
include "window.h"

SetWindow "Sinus",800,600,w_1
SetFont 12,32,0,""
SetColorKey 128,255,128
sys cb, gr, xa=250, ya=150, za, float r

cb= LoadBmp "cball/cball32.bmp",256,256
gr= LoadBmp "cball/ground_1c.bmp",800,600

While WinExit=0
SetBmp gr,0,0,800,600,0
SetBmp cb,cos(r*pi/180)*120+xa,sin(r*pi/180)*80+ya,256,256,za
SetBmp cb,-sin(r*pi/180)*120+xa+100,cos(r*pi/180)*80+ya+50,128,128,za
SetBmp cb,sin(r*pi/180)*120+xa+50,-cos(r*pi/180)*80+ya,96,96,za
SetBmp cb,-sin(r*pi/180)*120+xa+50,-cos(r*pi/180)*80+ya,64,64,za
za +=1: iF za=32  Then za=0
r  +=1: iF r>=360 Then r=0
DoEvents
SwapBuffers
WaitFrames 60
Wend
WinEnd


[attachment deleted by admin]
Title: Re: Screen Shots
Post by: Charles Pegge on March 05, 2012, 12:51:06 PM
Spheroids in a psychedelic landscape based on cosine RGB overflows.

Oxygen (in progress version)
projects/GDIWindow/Ray5.o2bas

(http://www.oxygenbasic.org/o2pics/pixel/Ray5.jpg)

Charles
Title: Re: Screen Shots
Post by: kryton9 on March 16, 2012, 02:57:21 PM
Nice stuff guys!