//+--------------------------------------------------------------------------+
//| |
//| 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);
}
//_________________________________________________________________________
}
}