捐赠 | 广告 | 注册 | 发布 | 上传 | 关于我们    
  粤ICP备10103342号-1 DELPHI盒子 | 盒子文章 | 盒子问答悬赏 | 最新更新 | 盒子检索 | 下载中心 | 高级搜索    
  精品专区 | 繁體中文 | 奖励公告栏 | 直通车账号登陆 | 关闭GOOGLE广告 | 临时留言    
盒子资源分类
全部展开 - 全部合拢
PickDemo (OpenGL演示)
关键字:PickDemo OpenGL 作图 直线 glProject
来 自:原创
平 台:Win9x,Win2k/NT,WinXP 下载所需:0 火柴
深浅度:中级 完成时间:2003/10/23
发布者:inrm 发布时间:2003/10/23
编辑器:DELPHI7 语  种:简体中文
分 类:绘图 下载浏览:1300/18902
加入到我的收藏
下载错误报错
登陆以后才能下载
 用户名:
 密 码:
自动登陆(30天有效)
图片如果打不开,说明流量不够了,请稍候下载……
试着用鼠标拖动三维空间里的一条直线(或其端点)...
本演示程序希望能为OpenGL爱好者带来些什么,也希望OpenGL高手们给予评价。

glProject和glUnProject是一对被众多OpenGL书籍所"遗忘"的函数,本例程专为其而作。

program PickDemo;

uses
  Windows, Messages, GL,GLu;   

const
  WND_TITLE = 'OpenGL Pick Demo by inRm';
  BUFSIZE = 32;   // Size of selection buffer.
type
  gl1f = glfloat;
  gl3f = array [0..2] of glfloat;
  gl4f = array [0..3] of glfloat;
var
  h_Wnd : HWND;                     // Global window handle
  h_DC  : HDC;                      // Global device context
  h_RC  : HGLRC;                    // OpenGL rendering context
  winW  : integer=800;              // window size
  winH  : integer=600;
   keys : Array[0..255] of Boolean;   // Holds keystrokes
  viewP :TviewPortArray;
  modeM,projM :T16DArray;
  // User vaiables
  Ldown,Rdown  :boolean;
  hit,eye : Integer;
  zPos :Tpoint;
  x0, y0 :Integer;    // mouse movement
  rx, ry :single;
  // Object position
  obj :array[1..2] of gl3f; //对象的空间坐标
  Pos :array[1..2] of gl3f; //对象的屏幕坐标
{------------------------------------------------------------------}
{  Function to convert int to string.                              }
{------------------------------------------------------------------}
function IntToStr(Num : Integer) : String;
begin
  Str(Num, result);
end;
function Vert( x,y,z :gl1f) :gl3f;
begin
  result[0]:=x;  result[1]:=y;  result[2]:=z;
end;
function Point(X, Y: Integer): TPoint;
begin
  Result.X:= X;  Result.Y:= Y;
end;
procedure setAxisList;
begin
  glNewList(1,GL_COMPILE);  //坐标线
    glColor3f(1,0.5,0.5); glLineWidth (1);//绘图直线时笔的宽度
    glBegin(GL_LINE_STRIP);
      glColor3f(1,0,1); glVertex3f( 0,0,0); glVertex3f( 4,0,0);
      glColor3f(0,1,0); glVertex3f( 0,0,0); glVertex3f( 0,3,0);
      glColor3f(0,0,1); glVertex3f( 0,0,0); glVertex3f( 0,0,2);
    glEnd;
  glEndList;
end;
{------------------------------------------------------------------}
{  Function to draw the actual scene                               }
{------------------------------------------------------------------}
procedure glDraw( Mode :integer);
  var h :integer;
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);    // Clear The Screen And The Depth Buffer
  glLoadIdentity();                                       // Reset The View
  glTranslatef(0,0,-eye);

  glRotatef( ry, 1,0,0);
  glRotatef( rx, 0,0,1);
  glColor3f(0, 0.1, 0.6);
  glCallList(1);
  glPointSize( 6);    glLineWidth(2);
  if mode = GL_SELECT then   glLoadName(1);
    glBegin(GL_POINTS);  glColor3f(1, 1, 0);
      if hit=1 then glColor3f(1, 0, 0) else glColor3f(1, 1, 0);
      glVertex3fv( @obj[1]);                //画第一点
    glEnd;
  if mode = GL_SELECT then   glLoadName(2);
    glBegin(GL_POINTS);  glColor3f(1, 1, 0);
      if hit=2 then glColor3f(1, 0, 0) else glColor3f(1, 1, 0);
      glVertex3fv( @obj[2]);                //画第二点
    glEnd;
  if mode = GL_SELECT then   glLoadName(3);
    glBegin( GL_LINES);
      if hit=3 then glColor3f(1, 0, 0) else glColor3f(1, 0.5, 0.5);
      glVertex3fv( @obj[1]);  glVertex3fv( @obj[2]);  //连接线
    glEnd;
  if mode = GL_SELECT then   glLoadName(0);
    glCallList(1);          //画坐标轴线
  if Ldown and(hit>0) then begin //画坐标指示线
    glColor3f( 0.5,0.5,0.5);
    glEnable( GL_LINE_STIPPLE); glLineStipple(1,$4444);
    if hit<3 then h:=hit else h:=1;
    glBegin( GL_LINE_STRIP);
      glVertex3fv( @obj[h]);      glVertex3f( obj[h,0],obj[h,1],0);
      glVertex3f( obj[h,0],0,0);  glVertex3f( 0,0,0);
      glVertex3f( 0,obj[h,1],0);  glVertex3f( obj[h,0],obj[h,1],0);
    glEnd;
    glDisable( GL_LINE_STIPPLE);
  end;
end;
{------------------------------------------------------------------}
{  Initialise OpenGL                                               }
{------------------------------------------------------------------}
procedure glInit();
begin
  glClearColor(0.0, 0.0, 0.0, 0.0);     // Black Background
//  glShadeModel(GL_SMOOTH);                 // Enables Smooth Color Shading
  glClearDepth(1.0);                       // Depth Buffer Setup
  glDepthFunc(GL_LESS);            // The Type Of Depth Test To Do
  glEnable(GL_DEPTH_TEST);                 // Enable Depth Buffer

  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);   //Realy Nice perspective calculations
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //控制混合方式
    glEnable(GL_BLEND);       //混合(透明)使能
    glEnable(GL_line_smooth);
    glEnable(GL_POINT_SMOOTH);
  setAxisList;
  rx:= -125;  ry:= -65; //视角
  eye:= 10;  //景深
  obj[1]:=Vert(-1, 2, 0.8);
  obj[2]:=Vert( 2,-1,-0.5);
end;
{------------------------------------------------------------------}
{  Handle window resize                                            }
{------------------------------------------------------------------}
procedure glResizeWnd(Width, Height : Integer);
begin
  winW:= width; winH:= Height;
  if (Height = 0) then Height := 1;   // prevent divide by zero exception
  glViewport(0, 0, Width, Height);    // Set the viewport for the OpenGL window
  glMatrixMode(GL_PROJECTION);        // Change Matrix Mode to Projection
  glLoadIdentity();                   // Reset View
  gluPerspective(45, Width/Height, 1, 100);  // Do the perspective calculations. Last value = max clipping depth

  glMatrixMode(GL_MODELVIEW);         // Return to the modelview matrix
  glLoadIdentity();                   // Reset View
end;
{------------------------------------------------------------------}
{  Processes all mouse Clicks                                      }
{------------------------------------------------------------------}
function doSelect(X, Y : Integer) :integer;
  var selectBuff : Array[0..23] of glUint;
begin
  glGetIntegerv(GL_VIEWPORT, @viewP);   // Viewport = [0, 0, width, height]
  glSelectBuffer(BUFSIZE, @selectBuff);
  glRenderMode(GL_SELECT);
  glInitNames;
  glPushName(32);

  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
    glLoadIdentity();
    gluPickMatrix(x, winH-y, 4, 4, viewP);      // Set-up pick matrix
    gluPerspective(45, winW/winH, 1, 100);  // Do the perspective calculations. Last value = max clipping depth
    glMatrixMode(GL_MODELVIEW);

    glDraw( GL_SELECT);

    glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  if glRenderMode(GL_RENDER)>0
    then result:= selectBuff[3]
    else result:= -1;
end;
//############ 获得对象的屏幕坐标 ################
function GetWinPos( h:integer) :gl3f;
  var wx,wy,wz :glDouble;  // 屏幕坐标
begin
  gluProject( obj[h,0],obj[h,1],obj[h,2], modeM,projM,viewP, @wx,@wy,@wz);
  result:= Vert( wx,wy,wz);
end;
//############ 将屏幕坐标转换为空间坐标 ################
function GetObjPos( x,y,z:gl1f) :gl3f;
  var px,py,pz :glDouble;  // 对象坐标
begin
  gluUnProject( x,y,z, modeM,projM,viewP, @px,@py,@pz);
  result:= Vert( px,py,pz);
end;
//============ 按下鼠标 =============
procedure MouseDown( hit, x,y : Integer);
  var i :integer;
begin
  Ldown:= TRUE;
  if hit<=0 then exit;
  zPos:= point(x,y); //很奇怪,这个变量无任何用处,但在这里却不能删除,否则就会黑屏!
  glGetDoublev( GL_Modelview_Matrix, @modeM);
  glGetDoublev(GL_Projection_Matrix, @projM);
  for i:= 1 to 2 do Pos[i]:= GetWinPos(i);//构件的屏幕坐标
  glDraw(GL_RENDER);
end;
//============= 移动鼠标 ==============
procedure MouseMove( hit, x,y, x0,y0 : Integer);
  var dx,dy, i :integer;
begin
  dx:= x-x0; dy:= y-y0;
  if hit<0 then begin rx:= rx+ (x-x0)/5; ry:= ry+ (y-y0)/5; end; //改变视角
  if hit<3 then
    obj[hit]:= GetObjPos( x, winH-y, GetWinPos( hit)[2]);  //直接将构件移动到新的位置
  if hit=3 then
    for i:= 1 to 2 do
      begin
      obj[i]:= GetObjPos( Pos[i][0]+dx,(Pos[i][1]-dy),Pos[i][2]);//将构件移动到新的位置
      Pos[i]:= GetWinPos(i);//构件的屏幕坐标
      end;
end;
{------------------------------------------------------------------}
{  Determines the application抯 response to the messages received  }
{------------------------------------------------------------------}
function WndProc(hWnd: HWND; Msg: UINT;  wParam: WPARAM;  lParam: LPARAM): LRESULT; stdcall;
  var x,y :integer;
begin
  case (Msg) of
    WM_CREATE:
      begin
        // Insert stuff you want executed when the program starts
      end;
    WM_CLOSE:
      begin
        PostQuitMessage(0);
        Result := 0
      end;
    WM_KEYDOWN:       // Set the pressed key (wparam) to equal true so we can check if its pressed
      begin
        keys[wParam] := True;
        Result := 0;
      end;
    WM_KEYUP:         // Set the released key (wparam) to equal false so we can check if its pressed
      begin
        keys[wParam] := False;
        Result := 0;
      end;
    WM_SIZE:          // Resize the window with the new width and height
      begin
        glResizeWnd(LOWORD(lParam),HIWORD(lParam));
        Result := 0;
      end;
    WM_LBUTTONDOWN: begin
      x0:= LoWord(lParam);  y0:= HiWord(lParam);
      MouseDown( hit, x0,y0 );
      Result := 0;
      end;
    WM_RBUTTONDOWN: begin
      x0:= LoWord(lParam);  y0:= HiWord(lParam);
      Rdown:= true;
      Result := 0;
      end;
    WM_LBUTTONUP: begin
      Ldown :=FALSE;
      Result := 0;
      end;
    WM_RBUTTONUP: begin
      Rdown :=FALSE;
      Result := 0;
      end;
    WM_MOUSEMOVE:begin
      x:= LoWord(lParam);  y:= HiWord(lParam);
      if not(Ldown or Rdown) then hit:= doSelect(x, y); //自由移动
      if Ldown then MouseMove( hit, x,y, x0,y0);        //拖动左键
      if Rdown then begin                               //拖动右键
        eye:= eye- (x-x0);                              //改变景深
        if eye>80 then eye:=80;   if eye<5 then eye:=5;
        end;
      x0:= x;  y0:= y;
      SetWindowText(h_Wnd, PChar('OpenGL Pick Demo by inRm ... Object number: '+IntToStr(hit)));
      Result := 0;
      end;
    WM_TIMER:
      // Add code here for all timers to be used.
    else
      Result := DefWindowProc(hWnd, Msg, wParam, lParam);    // Default result if nothing happens
  end;
end;
{---------------------------------------------------------------------}
{  Properly destroys the window created at startup (no memory leaks)  }
{---------------------------------------------------------------------}
procedure glKillWnd(Fullscreen : Boolean);
begin
  if Fullscreen then             // Change back to non fullscreen
    begin
    ChangeDisplaySettings(devmode(nil^), 0);
    ShowCursor(True);
    end;
  // Makes current rendering context not current, and releases the device
  // context that is used by the rendering context.
  if (not wglMakeCurrent(h_DC, 0)) then
    MessageBox(0, 'Release of DC and RC failed!', 'Error', MB_OK or MB_ICONERROR);
  // Attempts to delete the rendering context
  if (not wglDeleteContext(h_RC)) then
    begin
    MessageBox(0, 'Release of rendering context failed!', 'Error', MB_OK or MB_ICONERROR);
    h_RC := 0;
    end;
  // Attemps to release the device context
  if ((h_DC = 1) and (ReleaseDC(h_Wnd, h_DC) <> 0)) then
    begin
    MessageBox(0, 'Release of device context failed!', 'Error', MB_OK or MB_ICONERROR);
    h_DC := 0;
    end;
  // Attempts to destroy the window
  if ((h_Wnd <> 0) and (not DestroyWindow(h_Wnd))) then
    begin
    MessageBox(0, 'Unable to destroy window!', 'Error', MB_OK or MB_ICONERROR);
    h_Wnd := 0;
    end;
  // Attempts to unregister the window class
  if (not UnRegisterClass('OpenGL', hInstance)) then
    begin
    MessageBox(0, 'Unable to unregister window class!', 'Error', MB_OK or MB_ICONERROR);
    hInstance := 0;
    end;
end;
{--------------------------------------------------------------------}
{  Creates the window and attaches a OpenGL rendering context to it  }
{--------------------------------------------------------------------}
function glCreateWnd(Width, Height : Integer; Fullscreen : Boolean; PixelDepth : Integer) : Boolean;
var
  wndClass : TWndClass;         // Window class
  dwStyle : DWORD;              // Window styles
  dwExStyle : DWORD;            // Extended window styles
  dmScreenSettings : DEVMODE;   // Screen settings (fullscreen, etc...)
  PixelFormat : GLuint;         // Settings for the OpenGL rendering
  h_Instance : HINST;           // Current instance
  pfd : TPIXELFORMATDESCRIPTOR;  // Settings for the OpenGL window
begin
  h_Instance := GetModuleHandle(nil);       //Grab An Instance For Our Window
  ZeroMemory(@wndClass, SizeOf(wndClass));  // Clear the window class structure
  with wndClass do                    // Set up the window class
  begin
    style         := CS_HREDRAW or    // Redraws entire window if length changes
                     CS_VREDRAW or    // Redraws entire window if height changes
                     CS_OWNDC;        // Unique device context for the window
    lpfnWndProc   := @WndProc;        // Set the window procedure to our func WndProc
    hInstance     := h_Instance;
    hCursor       := LoadCursor(0, IDC_ARROW);
    lpszClassName := 'OpenGL';
  end;

  if (RegisterClass(wndClass) = 0) then  // Attemp to register the window class
  begin
    MessageBox(0, 'Failed to register the window class!', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit
  end;
  // Change to fullscreen if so desired
  if Fullscreen then
  begin
    ZeroMemory(@dmScreenSettings, SizeOf(dmScreenSettings));
    with dmScreenSettings do begin              // Set parameters for the screen setting
      dmSize       := SizeOf(dmScreenSettings);
      dmPelsWidth  := Width;                    // Window width
      dmPelsHeight := Height;                   // Window height
      dmBitsPerPel := PixelDepth;               // Window color depth
      dmFields     := DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL;
    end;
    // Try to change screen mode to fullscreen
    if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN) = DISP_CHANGE_FAILED) then
    begin
      MessageBox(0, 'Unable to switch to fullscreen!', 'Error', MB_OK or MB_ICONERROR);
      Fullscreen := False;
    end;
  end;
  // If we are still in fullscreen then
  if (Fullscreen) then
  begin
    dwStyle := WS_POPUP or                // Creates a popup window
               WS_CLIPCHILDREN            // Doesn't draw within child windows
               or WS_CLIPSIBLINGS;        // Doesn't draw within sibling windows
    dwExStyle := WS_EX_APPWINDOW;         // Top level window
    ShowCursor(False);                    // Turn of the cursor (gets in the way)
  end
  else
  begin
    dwStyle := WS_OVERLAPPEDWINDOW or     // Creates an overlapping window
               WS_CLIPCHILDREN or         // Doesn't draw within child windows
               WS_CLIPSIBLINGS;           // Doesn't draw within sibling windows
    dwExStyle := WS_EX_APPWINDOW or       // Top level window
                 WS_EX_WINDOWEDGE;        // Border with a raised edge
  end;
  // Attempt to create the actual window
  h_Wnd := CreateWindowEx(dwExStyle,      // Extended window styles
                          'OpenGL',       // Class name
                          WND_TITLE,      // Window title (caption)
                          dwStyle,        // Window styles
                          0, 0,           // Window position
                          Width, Height+27,  // Size of window
                          0,              // No parent window
                          0,              // No menu
                          h_Instance,     // Instance
                          nil);           // Pass nothing to WM_CREATE
  if h_Wnd = 0 then
  begin
    glKillWnd(Fullscreen);                // Undo all the settings we've changed
    MessageBox(0, 'Unable to create window!', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Try to get a device context
  h_DC := GetDC(h_Wnd);
  if (h_DC = 0) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to get a device context!', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Settings for the OpenGL window
  with pfd do
  begin
    nSize           := SizeOf(TPIXELFORMATDESCRIPTOR); // Size Of This Pixel Format Descriptor
    nVersion        := 1;                    // The version of this data structure
    dwFlags         := PFD_DRAW_TO_WINDOW    // Buffer supports drawing to window
                       or PFD_SUPPORT_OPENGL // Buffer supports OpenGL drawing
                       or PFD_DOUBLEBUFFER;  // Supports double buffering
    iPixelType      := PFD_TYPE_RGBA;        // RGBA color format
    cColorBits      := PixelDepth;           // OpenGL color depth
    cRedBits        := 0;                    // Number of red bitplanes
    cRedShift       := 0;                    // Shift count for red bitplanes
    cGreenBits      := 0;                    // Number of green bitplanes
    cGreenShift     := 0;                    // Shift count for green bitplanes
    cBlueBits       := 0;                    // Number of blue bitplanes
    cBlueShift      := 0;                    // Shift count for blue bitplanes
    cAlphaBits      := 0;                    // Not supported
    cAlphaShift     := 0;                    // Not supported
    cAccumBits      := 0;                    // No accumulation buffer
    cAccumRedBits   := 0;                    // Number of red bits in a-buffer
    cAccumGreenBits := 0;                    // Number of green bits in a-buffer
    cAccumBlueBits  := 0;                    // Number of blue bits in a-buffer
    cAccumAlphaBits := 0;                    // Number of alpha bits in a-buffer
    cDepthBits      := 16;                   // Specifies the depth of the depth buffer
    cStencilBits    := 0;                    // Turn off stencil buffer
    cAuxBuffers     := 0;                    // Not supported
    iLayerType      := PFD_MAIN_PLANE;       // Ignored
    bReserved       := 0;                    // Number of overlay and underlay planes
    dwLayerMask     := 0;                    // Ignored
    dwVisibleMask   := 0;                    // Transparent color of underlay plane
    dwDamageMask    := 0;                     // Ignored
  end;

  // Attempts to find the pixel format supported by a device context that is the best match to a given pixel format specification.
  PixelFormat := ChoosePixelFormat(h_DC, @pfd);
  if (PixelFormat = 0) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to find a suitable pixel format', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Sets the specified device context's pixel format to the format specified by the PixelFormat.
  if (not SetPixelFormat(h_DC, PixelFormat, @pfd)) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to set the pixel format', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Create a OpenGL rendering context
  h_RC := wglCreateContext(h_DC);
  if (h_RC = 0) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to create an OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Makes the specified OpenGL rendering context the calling thread's current rendering context
  if (not wglMakeCurrent(h_DC, h_RC)) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to activate OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Settings to ensure that the window is the topmost window
  ShowWindow(h_Wnd, SW_SHOW);
  SetForegroundWindow(h_Wnd);
  SetFocus(h_Wnd);

  // Ensure the OpenGL window is resized properly
  glResizeWnd(Width, Height);
  glInit();

  Result := True;
end;
{--------------------------------------------------------------------}
{  Main message loop for the application                             }
{--------------------------------------------------------------------}
function WinMain(hInstance :HINST; hPrevInstance :HINST; lpCmdLine :PChar; nCmdShow :Integer) :Integer; stdcall;
var
  msg : TMsg;
  finished : Boolean;
begin
  finished := False;
  // Perform application initialization:
  if not glCreateWnd(800, 600, false, 32) then
  begin
    Result := 0;
    Exit;
  end;
  // Main message loop:
  while not finished do
  begin
    if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then // Check if there is a message for this window
      begin
        if (msg.message = WM_QUIT)     // If WM_QUIT message received then we are done
        then finished := True
        else begin                               // Else translate and dispatch the message to this window
         TranslateMessage(msg);
          DispatchMessage(msg);
          end;
      end
    else
      begin
      glDraw(GL_RENDER);                           // Draw the scene
      SwapBuffers(h_DC);                  // Display the scene
      if(keys[VK_ESCAPE])then finished := True; // If user pressed ESC then set finised TRUE
      end;
  end;
  glKillWnd(FALSE);
  Result := msg.wParam;
end;

begin
  WinMain( hInstance, hPrevInst, CmdLine, CmdShow );
end.
Google
 
本站原创作品,未经作者许可,严禁任何方式转载;转载作品,如果侵犯了您的权益,请联系我们
龙脉加密锁 15元起 Grid++Report 报表 申请支付@网
 相关文章
没有相关文章
相关评论
共有评论7条
我要发表评论 查看全部评论
 
  DELPHI盒子版权所有 技术支持:深圳市麟瑞科技有限公司 1999-2024 V4.01 粤ICP备10103342号-1 更新RSS列表