Click here to Skip to main content
15,895,557 members
Articles / Programming Languages / C#

Planet 3D (Alias GL Earth)

Rate me:
Please Sign up or sign in to vote.
4.97/5 (23 votes)
13 Nov 2006CPOL2 min read 116.9K   7.9K   76  
OpenGL moving planet
//+--------------------------------------------------------------------------+
//|                                                                          |
//|                                Planet3D                                  |
//|                              Version 1.01                                |
//|                                                                          |
//|      OpenGL project using the GDImage flat API to create on the fly      |
//|     planet texture from files with smooth shading and ambient light.     |
//|                                                                          |
//|          The GDImage.dll unregistered version has no limitation,         |
//|             and all features of the API are fully functional.            |
//|                                                                          |
//|       Buying a commercial license removes the copyright nag screen.      |
//|                                                                          |
//+--------------------------------------------------------------------------+
//|                                                                          |
//|                         Author Patrice TERRIER                           |
//|                           copyright (c) 2006                             |
//|                                                                          |
//|                        pterrier@zapsolution.com                          |
//|                                                                          |
//|                          www.zapsolution.com                             |
//|                                                                          |
//+--------------------------------------------------------------------------+
//|                  Project started on : 10-26-2006 (MM-DD-YYYY)            |
//|                        Last revised : 11-13-2006 (MM-DD-YYYY)            |
//+--------------------------------------------------------------------------+

using System;
//using System.Collections.Generic;
//using System.ComponentModel;
//using System.Data;
using System.Drawing;
//using System.Text;
using System.Windows.Forms;

using System.Runtime.InteropServices;
//using System.Runtime;
//using System.IO;
//using Microsoft.Win32;

using Win32;
using GDImage;
using OpenGL;
using SkinEngine;

namespace Planet3D
{
    //Version 1.01
    //___________________________________________________________
    public delegate int CallBack(IntPtr hWnd, int wMsg, uint wParam, uint lParam);
    //___________________________________________________________

    public partial class MAIN_Form : Form
    {
        const int GLOBE = 0;                           // GLOBE texture
        const int STARS = 1;                           // STARS texture
        const int ID_CTRL  = 100;                      // GDImage Zoom control
        const int ID_GLOBE = 101;
        const int ID_STARS = 102;
        const int TIMER_MAX = 2;                       // To perform smooth animation

        static GI.ZGLTEXTURE[] mt = new GI.ZGLTEXTURE[2];

        static public IntPtr hFORM_Main = IntPtr.Zero; // Default to Zero
        static public IntPtr hGLcontrol = IntPtr.Zero; // Default to Zero

        static GI.ZGLFONT UseFont = new GI.ZGLFONT();
        static bool Animate = false;

        static int WasZoom = 0;
        static bool Zooming = false;

        //Version 1.01
        //____________________________________________________________
        //static float grDistance, grSpinX, grSpinY, grYincr, grXincr;
        [DllImport("USER32", EntryPoint = "SetWindowLongA")]
        public static extern int SetCallBack(IntPtr hWnd, int nIndex, CallBack lNewLong);
        static CallBack UseCallBack = null;
        static int GLwasX, GLwasY;
        static bool bMousing;
        static int ptLastMousePositX, ptLastMousePositY, ptCurrentMousePositX, ptCurrentMousePositY;
        static int ghGLproc;                             // OpenGL subclassing
        //____________________________________________________________

        static float grSpinY, grSpinX;
        static float grYincr, grXincr;

        public MAIN_Form()
        {
            InitializeComponent();

            // Create the OpenGL control
            hGLcontrol = GI.CreateGLcontrol(GL_Template, ID_CTRL);

            hFORM_Main = this.Handle;
            StartAnimation();

        }

        private void FORM_Load(object sender, EventArgs e)
        {
            // We need this to retrieve bitmap from resource
            SK.UseNameSpace = this.GetType().Namespace;

            // Use GetPixel(0, 0) for transparent color
            SK.UseTransparencyColorTopLeft = true;

            // Create buttons region and init button (to show enabled/disabled mode)
            SK.CreateButtonRegion(BTN_Up);
            SK.CreateButtonRegion(BTN_Left); 
            SK.CreateButtonRegion(BTN_Right);
            SK.CreateButtonRegion(BTN_Down);
            SK.CreateButtonRegion(BTN_Reset);
            SK.CreateButtonRegion(BTN_Pause);
            SK.CreateButtonRegion(BTN_SelectFile);
            SK.CreateButtonRegion(BTN_Start);

            if (hGLcontrol != IntPtr.Zero)
            {
                //Version 1.01
                //______________________________________________________________
                UseCallBack = new CallBack(glWndProc);
                ghGLproc = SetCallBack(hGLcontrol, Api.GWL_WNDPROC, UseCallBack);
                //______________________________________________________________

                OnOff.Checked = true;

                // Do not fit the texture into a square shape
                GI.DoNotSquareTexture();

                // This is our background image texture
                mt[GLOBE].FullName = Api.ExePath() + "Earth.jpg"; mt[GLOBE].ID = ID_GLOBE;
                // This is our default moving sprite texture
                mt[STARS].FullName = Api.ExePath() + "StarsNight.jpg"; mt[STARS].ID = ID_STARS;

                // Assign textures to mt[]
                SetGenTextures(2);

                // I am using a temporary ZGLTEXTURE structure 
                // to protect mt[] from being erased during 
                // call to SetMutipleGLTextureFrom32Bit.
                GI.ZGLTEXTURE[] temp = new GI.ZGLTEXTURE[mt.Length];
                for (int k = 0; k < mt.Length; k++) { temp[k] = mt[k]; }
                if (GI.CreateMutipleGLtextures(ref temp, mt.Length) == 0)
                {
                    ResetGlobe();

                    float[] LightAmbient = { 0.05f, 0.05f, 0.05f, 1.0f };
                    float[] LightDiffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
                    float[] LightPosition = { 20.0f, 0.0f, 30.0f, 1.0f };
                    GL.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, LightAmbient);   // Setup The Ambient Light
                    GL.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, LightDiffuse);   // Setup The Diffuse Light
                    GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, LightPosition); // Position The Light

                    GL.glShadeModel(GL.GL_SMOOTH); // Enable Smooth Shading
                    GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); // Do nicest perspective
                    GL.glEnable(GL.GL_COLOR_MATERIAL); // Enable Coloring Of Material	

                    GL.glEnable(GL.GL_TEXTURE_2D);

                    UseFont.fontName = "Arial";       // A True Type font
                    UseFont.fontHeight = 10;          // Size of the font
                    UseFont.fontWeight = Api.FW_BOLD; // Font style
                    GI.BuildGLfont(GI.GetGLDC(hGLcontrol), ref UseFont);

                    // When using the GDImage file selector
                    // start looking for pictures into the EXE folder.
                    GI.LoadSavePath(Api.ExePath(), true);
                }
            }
        }

        private void SetGenTextures(int n)
        {
            int[] textures = new int[n];
            GL.glGenTextures(n, textures);
            for (int k = 0; k < mt.Length; k++) { mt[k].Texture = textures[k]; }
        }

        private void StartAnimation()
        {
            // Use API WM_TIMER to avoid aggressive garbage collection 
            // to occur before Main ends.
            for (int T = 0; T < TIMER_MAX; T++)
            {
                Api.SetTimer(hFORM_Main, T + 1, 0, null);
            }
        }

        private void SetZoom(int zoom)
        {
            GI.SetGLzoom(hGLcontrol, zoom);
            GI.ResizeGLWindow(hGLcontrol);
        }

        private void UpdateZoom(int z)
        {
            SetZoom(z); RenderOpenGL(hGLcontrol);
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case Api.WM_TIMER:
                    RenderOpenGL(hGLcontrol);
                    m.Result = (IntPtr)0;
                    return;

                case Api.WM_COMMAND:
                    //  Zooming part
                    if (m.LParam == ZOOM_Track.Handle)
                    {// So much easier than trying to raise an event
                        // Warning, we are using polar coordinates there
                        // thus convert it to Degree
                        if (Zooming == false)
                        {
                            Zooming = true;
                            double range = ZOOM_Track.Maximum - ZOOM_Track.Minimum;
                            double increment = range / 90.0f;
                            int ZoomIs = (int)Math.Max(range - (ZOOM_Track.Value * increment), 1);

                            if (WasZoom < ZoomIs)
                            { for (int z = WasZoom; z < ZoomIs + 1; z++) UpdateZoom(z); }
                            else if (WasZoom > ZoomIs)
                            { for (int z = WasZoom; z > ZoomIs - 1; z--) UpdateZoom(z); }

                            WasZoom = ZoomIs;
                            Zooming = false;
                        }
                    }
                    break;

                case Api.WM_DESTROY:
                    DisposeGL(); // Free up OpenGL resources
                    break;
            }

            base.WndProc(ref m);

            if (m.Msg == Api.WM_COMMAND) Api.SetFocus(m.HWnd);            
        }

        //private void Form_KeyDown(object sender, KeyEventArgs e)
        //{
        //    bool Eat = false;
        //    switch ((int)e.KeyCode)
        //    {
        //        case Api.VK_LEFT:
        //        case Api.VK_RIGHT:
        //        case Api.VK_UP:
        //        case Api.VK_DOWN:
        //        case Api.VK_PGUP:
        //        case Api.VK_PGDN:
        //            Eat = true;
        //            break;
        //        default: break;
        //    }
        //    e.Handled = Eat;
        //}

        private void Form_PreviewKeydown(object sender, PreviewKeyDownEventArgs e)
        {
            int ZoomIs;
            switch ((int)e.KeyCode)
            {
                case Api.VK_LEFT: grXincr -= 0.01f; Animate = true; break;
                case Api.VK_RIGHT: grXincr += 0.01f; Animate = true; break;
                case Api.VK_UP: grYincr -= 0.01f; Animate = true; break;
                case Api.VK_DOWN: grYincr += 0.01f; Animate = true; break;
                case Api.VK_PGUP:
                    ZoomIs = GI.GetGLzoom(hGLcontrol);
                    if (ZoomIs > 1)
                    {
                        GI.SetGLzoom(hGLcontrol, ZoomIs - 1);
                        GI.ResizeGLWindow(hGLcontrol);
                    }
                    Animate = true;
                    break;
                case Api.VK_PGDN:
                    ZoomIs = GI.GetGLzoom(hGLcontrol);
                    if (ZoomIs < 100)
                    {
                        GI.SetGLzoom(hGLcontrol, ZoomIs + 1);
                        GI.ResizeGLWindow(hGLcontrol);
                    }
                    Animate = true;
                    break;
            }
        }

        // Free up resources
        private void DisposeGL()
        {
            for (int T = 0; T < TIMER_MAX; T++)
            {
                Api.KillTimer(hFORM_Main, T + 1);
            }
            // Delete OpenGL font.
            GI.DeleteGLFont(ref UseFont);
        }

        private void RenderOpenGL(IntPtr hContainer)
        {
            // Save the active planet zoom, 
            // then switch to a fixed zoom for the stellar background
            int ZoomIs = GI.GetGLzoom(hGLcontrol);
            SetZoom(45);

            GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
            GL.glLoadIdentity();

            // ***********************
            // Draw the Sky background
            // ***********************
            GL.glDisable(GL.GL_LIGHT0);         // Disable Light ZERO
            GL.glDisable(GL.GL_LIGHTING);       // Disable Lighting
            GL.glDisable(GL.GL_COLOR_MATERIAL); // Disable Coloring Of Material
            GL.glBindTexture(GL.GL_TEXTURE_2D, mt[STARS].Texture);

            // Disable Depth Test
            GL.glDisable(GL.GL_DEPTH_TEST);
            
            GL.glBegin(GL.GL_QUADS);
            GL.glTexCoord2f(0.0f, 0.0f); GL.glVertex3f(-60.0f, -50.0f, -80.0f); // Bottom left of texture and quad
            GL.glTexCoord2f(1.0f, 0.0f); GL.glVertex3f(60.0f, -50.0f, -80.0f); // Bottom right
            GL.glTexCoord2f(1.0f, 1.0f); GL.glVertex3f(60.0f, 50.0f, -80.0f); // Top right
            GL.glTexCoord2f(0.0f, 1.0f); GL.glVertex3f(-60.0f, 50.0f, -80.0f); // Top left
            GL.glEnd();
            // ***********************

            // Restore the previously saved Zoom to display the planet
            SetZoom(ZoomIs);

            // ***********************
            // Draw the Globe texture
            // ***********************
            GL.glBindTexture(GL.GL_TEXTURE_2D, mt[0].Texture);

            // Enable Depth Test
            GL.glEnable(GL.GL_DEPTH_TEST);

            GL.glEnable(GL.GL_LIGHT0);          // Enable Light ZERO
            GL.glEnable(GL.GL_LIGHTING);        // Enable Lighting
            GL.glEnable(GL.GL_COLOR_MATERIAL);  // Enable Coloring Of Material

            GL.glPushMatrix();
            double Radius = 4.5;
            double Twist = 0.0;
            GI.UseGLPolarView(Radius, Twist, grSpinY, grSpinX);
            int quadObj = GL.gluNewQuadric(); // Pointer to the Quadric Object (Return 0 If No Memory))
            if (quadObj != 0)
            {
                GL.gluQuadricNormals(quadObj, GL.GLU_SMOOTH);  // Create Smooth Normals
                GL.gluQuadricTexture(quadObj, GL.GL_TRUE);     // Create Texture Coords
                GL.gluSphere(quadObj, 1.5, 48, 48);
                GL.gluDeleteQuadric(quadObj);
            }
            GL.glPopMatrix();
            // ***********************

            // ***********************
            // Display coordinates
            // ***********************
            if (OnOff.Checked)
            {
                int UseColor = Api.ARGB(255, 128, 0, 0);
                int V = (int)grSpinY % 360;
                int H = Math.Abs((int)grSpinX % 360); if (H > 180) H = 360 - H;
                string MyStr = "Longitude " + H.ToString();
                GI.DrawGLText(hContainer, ref UseFont, 10, 10, MyStr, UseColor);
                int aLat = Math.Abs(V); V = 90 - (aLat % 90); if ((aLat % 180) > 90) V = (aLat % 180) - 90;
                MyStr = "Latitude " + V.ToString();
                GI.DrawGLText(hContainer, ref UseFont, 22, 10 + UseFont.fontHeight, MyStr, UseColor);
                MyStr = "Zoom " + ((int)ZOOM_Track.Value).ToString();
                GI.DrawGLText(hContainer, ref UseFont, 39, 10 + UseFont.fontHeight * 2, MyStr, UseColor);
            }
            // ***********************

            // ***********************
            // Draw the scene
            // ***********************
            GI.UpdateGLWindow(hContainer);
            // ***********************

            if (Animate)
            {
                grSpinY += grYincr;
                grSpinX += grXincr;
            }
        }

        private void ResetGlobe()
        {
            grSpinY = 75;
            grSpinX = 0;
            grYincr = 0f;
            grXincr = 0f;
            ZOOM_Track.Value = 50;
        }

        // ****************************************
        private void FORM_Close(object sender, EventArgs e)
        {
        }

        //***********************************************************
        // We use the .NET template to resize the GDImage control
        private void FORM_Resize(object sender, EventArgs e)
        {
            // Use the template to resize the GDImage OpenGL control
            Api.MoveWindow(hGLcontrol, GL_Template.Location.X, GL_Template.Location.Y, GL_Template.Width, GL_Template.Height, true);
            GI.ResizeGLWindow(hGLcontrol);
            RenderOpenGL(hGLcontrol);
        }

        private void BTN_Start_Click(object sender, EventArgs e)
        {
            Animate = true;
            grXincr = 0.05f;
        }

        private void BTN_Select_Click(object sender, EventArgs e)
        {
            GI.LoadSavePath(Api.ExePath(), true);
            string sFileName = GI.LoadDialog(hFORM_Main);
            if (sFileName != null)
            {
                GI.DoNotSquareTexture();
                int NamedTexture = mt[GLOBE].Texture;
                GI.UpdateNamedGLTextureFromFile(sFileName, NamedTexture);
            }
        }

        private void BTN_Pause_Click(object sender, EventArgs e)
        {
            Animate = false;
        }

        private void BTN_Reset_Click(object sender, EventArgs e)
        {
            Animate = false;
            ResetGlobe();
            GI.SetGLzoom(hGLcontrol, 0); GI.ResizeGLWindow(hGLcontrol);
            RenderOpenGL(hGLcontrol);

        }

        private void BTN_Up_Click(object sender, EventArgs e)
        {
            Animate = true; grYincr -= 0.05f;
        }

        private void BTN_Down_Click(object sender, EventArgs e)
        {
            Animate = true; grYincr += 0.05f;
        }

        private void BTN_Left_Click(object sender, EventArgs e)
        {
            Animate = true; grXincr -= 0.05f;
        }

        private void BTN_Right_Click(object sender, EventArgs e)
        {
            Animate = true; grXincr += 0.05f;
        }
        
        private void BTN_MouseEnter(object sender, EventArgs e)
        {
            Button btn = ((Button)sender);
            SK.USE_BTN_Image(btn, 5);
        }

        private void BTN_MouseLeave(object sender, EventArgs e)
        {
            Button btn = ((Button)sender);
            SK.USE_BTN_Image(btn, 1);
        }

        private void BTN_MouseUp(object sender, MouseEventArgs e)
        {
            Button btn = ((Button)sender);
            SK.USE_BTN_Image(btn, 1);
        }

        private void BTN_MouseDown(object sender, MouseEventArgs e)
        {
            Button btn = ((Button)sender);
            SK.USE_BTN_Image(btn, 2);
        }

        private void BTN_EnabledChanged(object sender, EventArgs e)
        {
            Button btn = ((Button)sender);
            SK.InitButton(btn);
        }

        //Version 1.01
        //_________________________________________________________________________
        public static int glWndProc(IntPtr hWnd, int wMsg, uint wParam, uint lParam)
        {
            int x, y;
            switch (wMsg)
            {
                case Api.WM_LBUTTONDOWN:
                    if (bMousing == false)
                    {
                        x = Api.LoWrd(lParam); y = Api.HiWrd(lParam);
                        ptLastMousePositX = x;
                        ptCurrentMousePositX = x;
                        ptLastMousePositY = y;
                        ptCurrentMousePositY = y;
                        bMousing = true;
                    }
                    if (Api.GetFocus() != hWnd) Api.SetFocus(hWnd);
                    break;
                case Api.WM_LBUTTONUP:
                    bMousing = false;
                    break;
                case Api.WM_MOUSEMOVE:
                    x = Api.LoWrd(lParam); y = Api.HiWrd(lParam);
                    if (GI.IsLButtonDown() == false)
                    {
                        bMousing = false;
                    }
                    else
                    {
                        if ((GLwasX != x) || (GLwasY != y))
                        {
                            ptCurrentMousePositX = x;
                            ptCurrentMousePositY = y;
                            if (bMousing)
                            {
                                grSpinX += (ptCurrentMousePositX - ptLastMousePositX);
                                grSpinY -= (ptCurrentMousePositY - ptLastMousePositY);
                            }
                            ptLastMousePositX = ptCurrentMousePositX;
                            ptLastMousePositY = ptCurrentMousePositY;
                        }
                        GLwasX = x; GLwasY = y;
                    }
                    break;
            }
            return Api.CallWindowProc(ghGLproc, hWnd, wMsg, wParam, lParam);
        }

        //_________________________________________________________________________

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer zapsolution
France France
I am a low level SDK programmer, focusing mainly on graphic imaging and multimedia applications.
I am using several languages, including C, C++, PowerBASIC, WinDev.
I wrote also a few demos in C#, but i never used DotNET in real code production.

Comments and Discussions