中国程序员联盟 正在重新改版中ing 不便之处还请见谅 改版后将内容涉及java delphi .net php
 
  首页 | 数据库开发 | 网络通讯 | 多线程 | 多媒体开发 | 图像处理 | 程序人生 | 系统函数 | 控件开发 | Web服务
 
  当前位置:笨鱼delphi技术网>数据库开发>开发应用>文章内容

delphi Working with OpenGL - An FAQ

来源: 关于: 发布时间:2007-06-23   [收藏] [推荐]
What do I need to write programs for OpenGL with Delphi?

Compared to other graphics libraries you need very little additional software. Microsoft provides two dynamic link libraries (DLLs) with Windows9x and WindowsNT called OpenGL32.DLL and GLU32.DLL, which are able to render on accelerated as well as unaccelerated hardware.

To actually use the DLLs you need an interface unit which loads the libraries and connects your program with them. Delphi 3.0 and above provide a unit named OpenGL.pas which does exactly this. But you can download other interface units (sometimes split into two units called gl.pas and glu.pas) from different Delphi servers. I'd recommend that all Delphi users (even Delphi 3+ programmers) download one of the newer units (in particular OpenGL12.zip from the JEDI web site) to take advantage of additional features like dynamic DLL loading, context creation help, extension support and others.


How do I get OpenGL to work with Delphi?

Getting your program working with OpenGL isn't very complicated, but it does involve some steps and handwritten code. The reason is that OpenGL is very closely connected to a device context of a window or bitmap, which cannot be handled in a drag'n'drop manner.

Two steps are needed to make a device context (DC) drawable by OpenGL:
- set up a pixel format for the specific DC and - connect the DC to OpenGL by creating a rendering context (RC) for it.

Here is typical RC creation:

procedure SetupPalette(DC: HDC; PFD: TPixelFormatDescriptor); 
var 
  nColors, I : Integer;
  lpPalette : PLogPalette;
  byRedMask,
  byGreenMask,
  byBlueMask : Byte;
  Palette : HPalette;
begin
  nColors:=1 shl Pfd.cColorBits; 
  GetMem(lpPalette,SizeOf(TLogPalette)+(nColors*SizeOf(TPaletteEntry))); 
  try
    lpPalette^.palVersion:=$300;
    lpPalette^.palNumEntries:=nColors;
    byRedMask :=(1 shl Pfd.cRedBits)-1;
    byGreenMask:=(1 shl Pfd.cGreenBits)-1;
    byBlueMask :=(1 shl Pfd.cBlueBits)-1;

{$ifopt R+} {$define RangeCheck} {$endif} {$R-}

    for I:=0 to nColors-1 do
    begin
      lpPalette^.palPalEntry[I].peRed 
        :=(((I shr Pfd.cRedShift) and byRedMask) *255) DIV byRedMask;
      lpPalette^.palPalEntry[I].peGreen
        :=(((I shr Pfd.cGreenShift) and byGreenMask)*255) DIV byGreenMask;
      lpPalette^.palPalEntry[I].peBlue 
        :=(((I shr Pfd.cBlueShift) and byBlueMask) *255) DIV byBlueMask;
      lpPalette^.palPalEntry[I].peFlags:=0;
    end;

{$ifdef RangeCheck} {$R+} {$undef RangeCheck} {$endif}

    Palette:=CreatePalette(lpPalette^);
    if (Palette <> 0) then
    begin
      SelectPalette(DC,Palette,False);
      RealizePalette(DC);
    end;
  finally
    FreeMem(lpPalette);
  end;
end;

type TRCOptions = set of (opDoubleBuffered,opGDI,opStereo); 
function CreateRenderingContext(DC: HDC; Options: TRCOptions; 
                                StencilBits: Byte): HGLRC;
// Set the OpenGL properties required to draw to the given canvas and
// create a rendering context for it.
var 
  PFDescriptor : TPixelFormatDescriptor;
  PixelFormat : Integer; 
begin
  FillChar(PFDescriptor,SizeOf(PFDescriptor),0);
  with PFDescriptor do
  begin
    nSize:=sizeof(PFDescriptor);
    nVersion:=1;
    dwFlags:=PFD_SUPPORT_OPENGL;
    if GetObjectType(DC) = OBJ_MEMDC then 
      dwFlags:=dwFlags or PFD_DRAW_TO_BITMAP
    else 
      dwFlags:=dwFlags or PFD_DRAW_TO_WINDOW;
    if opDoubleBuffered in Options then 
      dwFlags:=dwFlags or PFD_DOUBLEBUFFER;
    if opGDI in Options then 
      dwFlags:=dwFlags or PFD_SUPPORT_GDI;
    if opStereo in Options then 
      dwFlags:=dwFlags or PFD_STEREO; 
    iPixelType:=PFD_TYPE_RGBA;
    cColorBits:=32;
    cDepthBits:=32; 
    cStencilBits:=StencilBits;
    iLayerType:=Byte(PFD_MAIN_PLANE); 
  end;
  // 
  PixelFormat:=ChoosePixelFormat(DC,@PFDescriptor);
  SetPixelFormat(DC,PixelFormat,@PFDescriptor);
  // check the properties just set
  DescribePixelFormat(DC,PixelFormat,SizeOf(PFDescriptor),@PFDescriptor);
  with PFDescriptor do
    if (dwFlags and PFD_NEED_PALETTE) <> 0 then
      SetupPalette(DC,PFDescriptor);
  Result:=wglCreateContext(DC); 
end;

Note that there's no OpenGL call yet. All the functions do is set up a pixel format and create a rendering context (with creation of a proper color palette if one is needed). The returned handle is only needed while making a RC 'current' in the particular DC (function wglMakeCurrent) because, while each thread can have more than one rendering context, only one can be active (current) at a given time.

Once you have created a RC you can issue as many OpenGL calls as you wish.

Let's see how to actually create the OpenGL program: The easiest way to accomplish that is to take a window-like control in Delphi (TForm is a very good candidate for the first time) and use its OnCreate event to create a RC for the windows canvas:

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyContext:=CreateRenderingContext(Canvas.Handle,[opDoubleBuffer],0);
end;

If you don't want to animate your 3D scene you don't even need opDoubleBuffered, which occupies twice the memory as for a simple RC to maintain a back and a front buffer to draw to alternatively.

Now two steps remain:

- first, tell OpenGL about the window region it can draw to, giving it some instructions concerning the viewport, using gluPerspective and glViewport (see OpenGL.hlp for a description). The best place to do this is in the OnResize event:

procedure TForm1.FormResize(Sender: TObject);
begin
  wglMakeCurrent(Canvas.Handle,FMyContext);
  glViewport(0,0,Width,Height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(30,Width/Height,1,100);
  Refresh;
end;

- secondly, do your actual drawing in OnPaint. Cover your draw commands with calls to wglMakeCurrent, to activate and deactivate the RC on enter and exit of OnPaint:

procedure TForm1.FormPaint(Sender: TObject);
begin
  // activate the RC
  wglMakeCurrent(Canvas.Handle,FMyContext);
  // clear color and depth buffer
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  // initialize transformation pipeline
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;
  // now do the drawing calls:
  //:  
  //:
  // finally deactivate the RC
  wglMakeCurrent(0,0);
end;

Don't forget to delete the RC on program exit (wglDeleteContext). The code snippets above are taken from the sample included in OpenGL12.zip. There you'll find a complete and simple project.


How do I do texturing?

Texturing is a way to map a one, two or three-dimensional bitmap onto a polygonal surface, to improve image quality dramatically.

Consider a 2D bitmap and how it is used as a texture, since this image format is widely used under Windows. The main problem while texturing a polygon is mapping pixels of the texture image to 3D coordinates of the given polygon. For bitmap coordinates in 3D space we use the identifiers S, T and Q instead of X, Y and Z (S for one dimension, S, T and Q for three dimensions). You can consider the orientation of each of the coordinates according to your needs. For imaging the texture so that the image has an upright perspective, you would normally use S for horizontal and T for vertical.

Regardless of the actual image size S and T are always in the range 0..1 for one occurence of the image on the polygon. Values < 0 or > 1 will either set a border color, repeat the first (last) image pixel or repeat the entire image, depending on the state flags. The easiest way to specify how the image has to be mapped is to apply a specific texture coordinate to each vertex of the polygon you want to texture:

glBegin(GL_POLYGON);
  glTexCoord2f(0,0);
  glVertex3f(0,0,0);
  glTexCoord2f(1,0);
  glVertex3f(1,0,0);
  glTexCoord2f(1,1);
  glVertex3f(1,1,0);
  glTexCoord2f(0,1);
  glVertex3f(0,1,0);
glEnd; 

As you can see the texture coordinate must precede the actual vertex. This small example maps an image independent of its size onto a square of unit size. If the image does not have an aspect ratio of 1 (say 320x256 instead of 128x128) it will not be scaled uniformly.

Important: OpenGL requires all image pixel sizes to be a power of two (2,4,8,16,32...). There is usually an upper limit. The 1024x1024 pixels limit that MS and SGI DLLs have is quite large: you should use smaller images. With the broad introduction of texture compression this limit is certain to be extended.

To do the actual texturing with Delphi (or by other means) there are four steps:

  1. - load an image into host memory
  2. - transfer the image to your OpenGL rendering context
  3. - set the desired options (don't forget to enable texturing) and
  4. - specify texture coordinates while issuing vertices

As always in OpenGL you need an active rendering context before any gl call. By far the hardest job is loading a bitmap into OpenGL. I use my own loader routine, which should handle most if not all of the possible pixel formats available. You can easily adapt it to your needs:

procedure TTexture.PrepareImage; 
// load texture to OpenGL subsystem 

type PPixelArray = ^PPixelArray; 

TPixelArray = array [0..0] of Byte; 

var Data : PPixelArray; BMInfo : TBitmapInfo; I,ImageSize : Integer; Temp : Byte; MemDC : HDC;

begin with BMinfo.bmiHeader do begin // make image data available (i.e load a picture into Image) Image.DataNeeded; // let Windows do any conversion to OpenGL's internal format we use, // create a description of the required image format FillChar(BMInfo,SizeOf(BMInfo),0); biSize:=sizeof(TBitmapInfoHeader); biBitCount:=24; biWidth:=RoundUpToPowerOf2(Image.Width); biHeight:=RoundUpToPowerOf2(Image.Height); ImageSize:=biWidth*biHeight; biPlanes:=1; biCompression:=BI_RGB;

// a dummy DC for the GetDIBits call below MemDC:=CreateCompatibleDC(0); // a piece of memory to place the bitmap bits into GetMem(Data,ImageSize*3); try // get the actual bits of the image GetDIBits(MemDC,Image.Bitmap,0,biHeight,Data,BMInfo,DIB_RGB_COLORS); // now set the bits depending on the features supported by OpenGL if GL_EXT_bgra then // BGR extension avoids color component swapping glTexImage2d(GL_TEXTURE_2D,0,3,biWidth,biHeight,0, GL_BGR_EXT,GL_UNSIGNED_BYTE,Data) else begin // no BGR support, so we must swap the color components by hand // switch off range checking for color swapping, make sure we // restore the original state {$ifopt R+} {$define RangeCheck} {$R-} {$endif} for I:=0 TO ImageSize-1 do //swap blue with red begin Temp:=Data[I*3]; Data[I*3]:=Data[I*3+2]; Data[I*3+2]:=Temp; end; // restore range check, if previously activated {$ifdef RangeCheck} {$undef RangeCheck} {$R+} {$endif} glTexImage2d(GL_TEXTURE_2D,0,3,biWidth,biHeight,0, GL_RGB,GL_UNSIGNED_BYTE,Data); end; finally FreeMem(Data); DeleteDC(MemDC); Image.ReleaseData; end; end; end;

My TTexture class has an Image property which is a simple TPicture class. By calling Image.LoadFromFile(FileName) you can load a bitmap from disk into main memory. In TTexture it is done by calling Image.DataNeeded. Conversely, Image.ReleaseData empties the Image since we don't need it any longer after it has been transferred to OpenGL.

One problem while loading an image is that OpenGL expects its color components in RGB order (remember we use a 24-bit image), which is the way a pixel is described in video memory. For some reason, Microsoft has introduced the BGR format. Because our image is stored in a Windows HBitmap (BGR format), all pixels must be changed to RGB. The SGI OpenGL for Windows has an extension for that situation which you can check for during context activation:

Buffer:=StrPas(PChar(glGetString(GL_EXTENSIONS))); 
if Pos('GL_EXT_bgra',Buffer) > 0 then 
  GL_EXT_bgra:=True 
else 
  GL_EXT_bgra:=False;

The interface unit in OpenGL12.zip handles extension detection automatically. WIth the release of OpenGL version 1.2 you won't have to deal with exception like the one above, because there will be many new common pixel formats (RGB 555, BGR 565 etc.).>/p>

If you encounter problems implementing the rounding function used in the loader routine, here is one solution:

function TTexture.RoundUpToPowerOf2(Value: Integer): Integer; 
var 
  LogTwo : Extended; 
begin 
  LogTwo:=log2(Value); 
  if Trunc(LogTwo) < LogTwo then 
    Result:=Trunc(Power(2,Trunc(LogTwo)+1)) 
  else 
    Result:=value; 
end; 

At this point we have almost all that's needed for texturing. The last step is setting up how OpenGL should apply the texture while rendering:

procedure TTexture.PrepareParams; 
begin 
  glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); 
  glPixelStorei(GL_UNPACK_ALIGNMENT,4); 
  glPixelStorei(GL_UNPACK_ROW_LENGTH,0); 
  glPixelStorei(GL_UNPACK_SKIP_ROWS,0); 
  glPixelStorei(GL_UNPACK_SKIP_PIXELS,0);

  case FTextureWrap of 
    twBoth : begin 
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); 
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); 
    end; 

    twNone : begin 
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); 
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); 
    end; 

    twHorizontal : begin 
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); 
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); 
    end; 

    twVertical : begin 
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); 
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); 
    end; 
  end; 

  case FMinFilter of 
    miNearest :
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);

    miLinear : glTexParameteri(GL_TEXTURE_2D, 
                               GL_TEXTURE_MIN_FILTER,GL_LINEAR); 

    miNearestMipmapNearest : 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                    GL_NEAREST_MIPMAP_NEAREST); 
    miLinearMipmapNearest : 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                      GL_LINEAR_MIPMAP_NEAREST); 

    miNearestMipmapLinear : 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                      GL_NEAREST_MIPMAP_LINEAR); 
    miLinearMipmapLinear : 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                      GL_LINEAR_MIPMAP_LINEAR); 
  end; 

  case FMagFilter of 
    maNearest : 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
    maLinear : 
      glTexParameteri(GL_TEXTURE_2D,G L_TEXTURE_MAG_FILTER,GL_LINEAR); 
  end; 

  case FTextureMode of 
    tmDecal : glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL); 
    tmModulate : glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,
                           GL_MODULATE); 
    tmBlend : glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_BLEND); 
    tmReplace : glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); 
  end; 
end; 

It would be far out of scope to describe what all the options do. I recommend that you read OpenGL.hlp in the Delphi\Help directory and experiment with the parameters in the procedures. The variables FTextureWrap, FMinFilter, FMagFilter and FTextureMode are simple sets of the values in the case statements they apply to.

If you use one of the mipmap options in FMinFilter you have to adjust the loader function as well. Good starting parameters are miNearest/maNearest for the filters and tmModulate (with light calculations) or tmDecal (without) for the texture mode.

If you want to load multiple textures and quickly switch between them, you should consider using texture objects. These objects are simple integer numbers describing a specific set of parameters and a texture image (bitmap). Texture objects are very similar to display lists and can even be shared between different contexts, but have a different name space. All you have to do is to bind such a texture object to the current context by calling glBindTexture(GL_TEXTURE_2D,FHandle) every time you either want to set up the object or to use it.

To get a valid texture object call glGenTextures(1,@FHandle).Free it with glDeleteTextures(1,@FHandle).

Don't search in OpenGL.hlp for any of the texture object calls. They are quite new and not covered in the current version of the help file (even in Delphi 4).

To sum up so far, the following sequence enables the use of textures in your OpenGL program:

- glGenTextures(1,@FHandle)
- glBindTexture(GL_TEXTURE_2D,FHandle)
- PrepareImage
- PrepareParams
- glEnable(GL_TEXTURE_2D)
- .... any glTexCoord and glVertex call combination
- glDeleteTextures(1,@FHandle) (will free used texture memory as well)


How can I run an application fullscreen?

Running an application full screen means that the application window covers the entire desktop area. This is often necessary because some video cards can only accelerate full screen apps; but you may also often want to ensure that your program is the only one visible to the user.

Running fullscreen isn't exclusive to OpenGL, DirectX or 3D in general. Strictly speaking, fullscreen operation only requires setting the window state to wsMaximize. However, asking for fullscreen operation has other implications. You may want to let the user choose a specific color and pixel resolution or you might want to run your program in a fixed resolution (very important, since not all video cards support all resolutions and often a game or other 3D application has to run in a different - - mostly lower - resolution than the user's everyday work requires).

So the complete question is "How can I run an application fullscreen in a specific color and pixel resolution without re-booting?"

The function ChangeDisplaySettings is the key to this. Depending on the video driver, you can set many video modes dynamically, without rebooting the computer:

function SetFullscreenMode(ModeIndex: Integer) :Boolean; 
// changes to the video mode given by 'ModeIndex' 
var 
  DeviceMode : TDevMode; 
begin 
  with DeviceMode do 
  begin 
    dmSize:=SizeOf(DeviceMode); 
    dmBitsPerPel:=VideoModes[ModeIndex].ColorDepth; 
    dmPelsWidth:=VideoModes[ModeIndex].Width; 
    dmPelsHeight:=VideoModes[ModeIndex].Height; 
    dmFields:=DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT; 
    // if mode set failed, we'll just run in windowed mode 
    Result:=ChangeDisplaySettings
                (DeviceMode, CDS_FULLSCREEN) = DISP_CHANGE_SUCCESSFUL; 
    if Result then ScreenModeChanged:=True; 
    if ModeIndex = 0 then ScreenModeChanged:=False; 
  end; 
end;

Notice the global variable VideoModes in this example. You need to enumerate all available video modes which can be set dynamically and store them into a structure like VideoModes, to restrict the modes the application will try to set:

const 
  MaxVideoModes = 200; // this isn't very much actually 
type TVideoMode = record 
  Width, 
  Height, 
  ColorDepth : Word; 
  Description : String[20]; 
end; 

var 
  VideoModes : array[0..MaxVideoModes] of TVideoMode;
  NumberVideomodes : Integer = 1; // 1 because we have a default mode 

This makes our example much larger but you can enhance functionality very usefully by implementing it. As an alternative, you can substitute VideoModes in the above function with fixed values (say 640, 480, 16).

Enumerating all video modes is done by EnumDisplaySettings:

procedure ReadVideoModes; 
var 
  I, ModeNumber : Integer; 
  done : Boolean; 
  DeviceMode : TDevMode; 
  DeskDC : HDC; 

begin // prepare 'default' entry with VideoModes[0] do

try DeskDC:=GetDC(0); ColorDepth:=GetDeviceCaps(DeskDC,BITSPIXEL); Width:=Screen.Width; Height:=Screen.Height; Description:='default'; finally ReleaseDC(0,DeskDC); end; // enumerate all available video modes ModeNumber:=0; done:=False; repeat done:=not EnumDisplaySettings(nil,ModeNumber,DeviceMode); TryToAddToList(DeviceMode); Inc(ModeNumber); until (done or (NumberVideomodes >= MaxVideoModes)); // low-res modes don't always enumerate, ask about them explicitly with DeviceMode do begin dmBitsPerPel:=8; dmPelsWidth:=42; dmPelsHeight:=37; dmFields:=DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT; // make sure the driver doesn't just answer yes to all tests if ChangeDisplaySettings(DeviceMode,CDS_TEST or CDS_FULLSCREEN) <> DISP_CHANGE_SUCCESSFUL then begin I:=0; while (I < NumberLowResModes-1) and (NumberVideoModes < MaxVideoModes) do begin dmSize:=Sizeof(DeviceMode); dmBitsPerPel:=LowResModes[I].ColorDepth; dmPelsWidth:=LowResModes[I].Width; dmPelsHeight:=LowResModes[I].Height; dmFields:=DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT; TryToAddToList(DeviceMode); Inc(I); end; end; end; end;

This function is quite straightforward. There are two parts to consider. The first is the standard way to enumerate the video modes. The second ensures that all low-res modes are tested as well. For this you need to supply a list of low-res modes:

type TLowResMode = record
  Height, 
  ColorDepth : Word;
end;

const 
  NumberLowResModes = 60;

LowResModes : array[0..NumberLowResModes-1] of TLowResMode =(
             (Width:320;Height:200;ColorDepth: 8),
             (Width:320;Height:200;ColorDepth:15),
             (Width:320;Height:200;ColorDepth:16),
             (Width:320;Height:200;ColorDepth:24),
             (Width:320;Height:200;ColorDepth:32),
             (Width:320;Height:240;ColorDepth: 8), 
             (Width:320;Height:240;ColorDepth:15),
             (Width:320;Height:240;ColorDepth:16), 
             (Width:320;Height:240;ColorDepth:24),
             (Width:320;Height:240;ColorDepth:32), 
             (Width:320;Height:350;ColorDepth: 8),
             (Width:320;Height:350;ColorDepth:15), 
             (Width:320;Height:350;ColorDepth:16),
             (Width:320;Height:350;ColorDepth:24), 
             (Width:320;Height:350;ColorDepth:32),
             (Width:320;Height:400;ColorDepth: 8), 
             (Width:320;Height:400;ColorDepth:15),
             (Width:320;Height:400;ColorDepth:16), 
             (Width:320;Height:400;ColorDepth:24),
             (Width:320;Height:400;ColorDepth:32), 
             (Width:320;Height:480;ColorDepth: 8),
             (Width:320;Height:480;ColorDepth:15), 
             (Width:320;Height:480;ColorDepth:16),
             (Width:320;Height:480;ColorDepth:24), 
             (Width:320;Height:480;ColorDepth:32),
             (Width:360;Height:200;ColorDepth: 8), 
             (Width:360;Height:200;ColorDepth:15),
             (Width:360;Height:200;ColorDepth:16), 
             (Width:360;Height:200;ColorDepth:24),
             (Width:360;Height:200;ColorDepth:32), 
             (Width:360;Height:240;ColorDepth: 8),
             (Width:360;Height:240;ColorDepth:15), 
             (Width:360;Height:240;ColorDepth:16),
             (Width:360;Height:240;ColorDepth:24), 
             (Width:360;Height:240;ColorDepth:32),
             (Width:360;Height:350;ColorDepth: 8), 
             (Width:360;Height:350;ColorDepth:15),
             (Width:360;Height:350;ColorDepth:16), 
             (Width:360;Height:350;ColorDepth:24),
             (Width:360;Height:350;ColorDepth:32), 
             (Width:360;Height:400;ColorDepth: 8),
             (Width:360;Height:400;ColorDepth:15), 
             (Width:360;Height:400;ColorDepth:16),
             (Width:360;Height:400;ColorDepth:24), 
             (Width:360;Height:400;ColorDepth:32),
             (Width:360;Height:480;ColorDepth: 8), 
             (Width:360;Height:480;ColorDepth:15),
             (Width:360;Height:480;ColorDepth:16), 
             (Width:360;Height:480;ColorDepth:24),
             (Width:360;Height:480;ColorDepth:32), 
             (Width:400;Height:300;ColorDepth: 8),
             (Width:400;Height:300;ColorDepth:15), 
             (Width:400;Height:300;ColorDepth:16),
             (Width:400;Height:300;ColorDepth:24), 
             (Width:400;Height:300;ColorDepth:32),
             (Width:512;Height:384;ColorDepth: 8), 
             (Width:512;Height:384;ColorDepth:15),
             (Width:512;Height:384;ColorDepth:16), 
             (Width:512;Height:384;ColorDepth:24),
             (Width:512;Height:384;ColorDepth:32)
            );

Now, the function TryToAddToList:

procedure TryToAddToList(DeviceMode: TDevMode); 
// Adds a video mode to the list if it's not a duplicate and can actually be set. 
var 
  I : Integer; 
begin 
  // See if this is a duplicate mode (can happen because of refresh 
  // rates, or because we explicitly try all the low-res modes) 

for I:=1 to NumberVideomodes-1 do with DeviceMode do if ( (dmBitsPerPel = VideoModes[I].ColorDepth) and (dmPelsWidth = VideoModes[I].Width) and (dmPelsHeight = VideoModes[I].Height)) then Exit; // it's a duplicate mode // do a mode set test (doesn't actually do the mode set, but reports // whether it would have succeeded). if ChangeDisplaySettings(DeviceMode,CDS_TEST or CDS_FULLSCREEN) <>DISP_CHANGE_SUCCESSFUL then Exit; // it's a new, valid mode, so add this to the list with DeviceMode do begin VideoModes[NumberVideomodes].ColorDepth:=dmBitsPerPel; VideoModes[NumberVideomodes].Width:=dmPelsWidth; VideoModes[NumberVideomodes].Height:=dmPelsHeight; VideoModes[NumberVideomodes].Description:= Format('%d x %d, %d bpp',[dmPelsWidth,dmPelsHeight,dmBitsPerPel]); end; Inc(NumberVideomodes); end;

To make your fullscreen implementation complete, you'd need a function to restore the default video mode, after your program exits:

procedure RestoreDefaultMode; 
// restores default desktop video mode 
var 
  T : TDevMode absolute 0; // a little trick to create a nil pointer 
begin 
  // Since the first parameter must be a var, we cannot use nil directly.
  // Instead we use a variable with an absolute address of 0. 
  ChangeDisplaySettings(T,CDS_FULLSCREEN); 
end; 

[浏览: 次]   
上一篇:delphi Making Forms Work: Part IV   下一篇:delphi delphi处理流
[收藏] [推荐] [返回顶部] [打印本页] [关闭窗口]  
    评论加载中…
google adsense热点文章
·delphi Delphi_三谈多态——善用virtua
·delphi 条形码处理
·delphi Delphi_三层开发基本概念介绍
·delphi 汉字转拼音码(上)
·delphi Olevariant
·delphi CS构架下的客户端自动更新程序
·delphi 在Dephi中使用TStream读写数据
·delphi 汉字转拼音码(下)
·delphi delphi处理流
·delphi 关于使用COM对象的方法
·delphi MTS组件——从理论到实践
·delphi 汉字转拼音码(中3)
     delphi技术网 | firefox 下载 | Avant Browser下载 | dedecms 技术网 | drupal 爱好者 | php 技术网
  Copyright@www.delphichm.com,2006-2009.All Rights Reserved.
 
程序员联盟 | delphi Java .net|QQ:707102932