Search code examples
opengldelphi-10-seattleopengl-compat

Colored text in OpenGL


I can get a rotating letter, but cannot color it. Could you check please what is wrong?

unit frmMain;

interface

uses
  Winapi.Windows, Vcl.Forms, System.Classes, Vcl.ExtCtrls;

type
  TfrmGL = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
  private const
    GLF_START_LIST = 1;
    NUM_LISTS = 1;
  private
    _dc: HDC;
    _hrc: HGLRC;
    _ra: Single;
    procedure _setDCPixelFormat();
  protected
    procedure Paint(); override;
    procedure Resize(); override;
    procedure DoCreate(); override;
  public
    destructor Destroy(); override;
  end;

var
  frmGL: TfrmGL;

implementation

uses
  Winapi.OpenGL, Vcl.Graphics;

{$R *.DFM}

procedure TfrmGL.Paint();
const
  Litera: AnsiString = #0; //The "V" is the first and only symbol in the list, therefore index 0
begin
  inherited;
  glLoadIdentity();
  glTranslatef(0.0, 0.0, -6.0);
  glRotatef(10.0, 1.0, 0.0, 0.0); //Rotating through 10 degrees around axis X
  glRotatef(_ra, 0.0, 1.0, 0.0); // Rotating around axis Y
  glTranslatef(-0.35, 0.0, 0.1); // Make the letter rotate around its center
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glPushAttrib(GL_LIST_BIT);
  glListBase(GLF_START_LIST);
  glCallLists(1, GL_UNSIGNED_BYTE, PAnsiChar(Litera));
  glPopAttrib();
  SwapBuffers(_dc);
end;

procedure TfrmGL.Resize();
begin
  inherited;
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(15.0, ClientWidth / ClientHeight, 1.0, 20.0);
  glViewport(0, 0, ClientWidth, ClientHeight);
  glMatrixMode(GL_MODELVIEW);
  InvalidateRect(Handle, nil, False);
end;

procedure TfrmGL.Timer1Timer(Sender: TObject);
begin
  _ra := _ra - 0.5;
  if _ra < 0 then _ra := 360.0;
  InvalidateRect(Handle, nil, False);
end;

procedure TfrmGL._setDCPixelFormat();
var
  nPixelFormat: Integer;
  pfd: TPixelFormatDescriptor;
begin
  FillChar(pfd, SizeOf(pfd), 0);
  pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
  //pfd.cDepthBits := 32;
  nPixelFormat := ChoosePixelFormat(_dc, @pfd);
  SetPixelFormat(_dc, nPixelFormat, @pfd);
end;

destructor TfrmGL.Destroy();
begin
  glDeleteLists(GLF_START_LIST, NUM_LISTS);
  wglMakeCurrent(0, 0);
  wglDeleteContext(_hrc);
  ReleaseDC(Handle, _dc);
  DeleteDC(_dc);
  inherited;
end;

procedure TfrmGL.DoCreate();
begin
  inherited;
  _ra := 0;
  Canvas.Font.Style := [];
  Canvas.Font.Color := clRed;
  _dc := GetDC(Handle);
  _setDCPixelFormat();
  _hrc := wglCreateContext(_dc);
  wglMakeCurrent(_dc, _hrc);
  glClearColor(0.3, 0.4, 0.6, 1.0);
  glColor3f(1.0, 0.0, 0.0); //This does not have any effect
  //makeRasterFont;
  //p1 = graphical device context
  //p2 = from which character to start (86 = code of letter "V")
  //p3 = how many symbols to generate
  //p5 = letter 3D model precision (0 = as in the source font)
  //p6 = 3D depth of the letter
  wglUseFontOutlinesW(Canvas.Handle, 86, NUM_LISTS, GLF_START_LIST, 0, 0.15, WGL_FONT_POLYGONS, nil);
  //Light source initialization
  glEnable(GL_DEPTH_TEST); // Enable depth test
  glEnable(GL_LIGHTING); // Enable lighting
  glEnable(GL_LIGHT0); // Turn on the light source 0
end;

end.

Solution

  • When lighting (GL_LIGHTING) is enabled, then the color which is associated, is taken from the material parameters (glMaterial).

    If you still want to use the current color attribute (which is set by glColor), then you have to enable GL_COLOR_MATERIAL and to set the color material paramters (glColorMaterial):

    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    

    See also Basic OpenGL Lighting.


    Since the diffuse and specular light depends on the normal vector of the surface, the normal vector attribute (glNormal) which is associated to the vertices, has to be set.
    Of course the light parameters glLight have to be set, too.

    I've you don't have set the proper parameters, then I recommend to disable lighting. Skip the line:

    glEnable(GL_LIGHTING);

    Once lighting is enabled, the it can be disabled again by

    glDisable(GL_LIGHTING);