Odd Font Problem

I’m using a font class similar to Nehe’s tutorial(see below) to print onto the screen, but nothing shows up until the window resized. Does anyone know the cause of this?

// Font.h

#pragma once

#include "stdafx.h"


class Font
{
    enum
    {
        NUM_CHARACTER   = 256
    };

    GLuint m_base;

    void BuildFont(CDC& dc, CFont& font);
public:
    Font(CDC& dc, CFont& font);


    Font(CDC& dc, const char* name,
         int point);

    ~Font();

    void print(const std::string& str, GLdouble x, GLdouble y) const;
};
#include "stdafx.h"
#include "Font.h"

void Font::BuildFont(CDC& dc, CFont& font)
{

    m_base = glGenLists(NUM_CHARACTER);

 
    CFont* oldFont = dc.SelectObject(&font);


    // build display list
    wglUseFontBitmaps(dc.m_hDC, 0, NUM_CHARACTER,
                      m_base);
    
    dc.SelectObject(oldFont);

}

Font::Font(CDC& dc, 
           CFont& font)
{
 //   glPushAttrib(GL_COLOR_BUFFER_BIT);
 //   glColor3d(r, g, b);
    BuildFont(dc, font);

   // glPopAttrib();
}

Font::Font(CDC& dc, const char* name, int point)
{
    CFont font;

    font.CreatePointFont(point, name, &dc);
    
    BuildFont(dc, font);

    font.DeleteObject();

}

Font::~Font()
{
    glDeleteLists(m_base, NUM_CHARACTER);
}

void Font::print(const std::string& str, GLdouble x, GLdouble y) const
{
    glRasterPos2d(x, y);                   // move raster position to (x, y)


    glPushAttrib(GL_LIST_BIT);             // push the display list bits
    glListBase(m_base);  

    ///////////////////////////////////////////
    // WARNING! ASSUMES char is unsigned
    ///////////////////////////////////////////
    glCallLists(static_cast<GLsizei>(str.length()), 
                GL_UNSIGNED_BYTE, str.c_str());

    glPopAttrib();
}

Are you issuing a draw after you print the text?

the OnSize handler repaints the screen, it sounds like you’re leaving out a repaint somewhere.

Ok, I did a little clean up of the font code, since the CDC could be found by wglGetCurrentDC, but everything else is the same.

Are you issuing a draw after you print the text?

No, I’m drawing the text just before the call to glFlush.

the OnSize handler repaints the screen, it sounds like you’re leaving out a repaint somewhere.

Yes, something to do with the first repaint not drawing the right font. In fact, it appears the first repaint is not creating the right font, but the triangle is being drawn.

Here is code from the view class that I think is relevant. This view is inherited by other views using different documents. It’s more or less test code, however. It recreates the font each time in the repaint.

// UEditView.cpp : implementation of the UEditView class
//

#include "stdafx.h"
#include "Font.h"
#include "UEdit.h"

#include "UEditDoc.h"
#include "UEditView.h"
#include ".\ueditview.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// UEditView

IMPLEMENT_DYNCREATE(UEditView, CScrollView)

BEGIN_MESSAGE_MAP(UEditView, CScrollView)
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
    ON_WM_CREATE()
    ON_WM_SIZE()
    ON_WM_ERASEBKGND()
    ON_WM_DESTROY()
END_MESSAGE_MAP()

// UEditView construction/destruction

UEditView::UEditView() 
: m_active(false),
  m_fullscreen(false)
{
	// TODO: add construction code here
    m_font = 0;
}

UEditView::~UEditView()
{
}

BOOL UEditView::PreCreateWindow(CREATESTRUCT& cs)
{
    // OpenGL can only render to the client area.
    // It cannot render to child windows or siblings
    cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

	return CScrollView::PreCreateWindow(cs);
}

// UEditView drawing

void UEditView::OnDraw(CDC* pDC)
{
	UEditDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// Select the palette
    CPalette* oldPal = pDC-&gt;SelectPalette(&m_palette, false);
    pDC-&gt;RealizePalette();

    if (!wglMakeCurrent(pDC-&gt;m_hDC, m_hrc)) {
        TRACE("wglMakeCurrent Failed %d
", GetLastError());
        return;
    }

    DrawScene();

    SwapBuffers(pDC-&gt;m_hDC);

    if (oldPal) 
    {
        pDC-&gt;SelectPalette(oldPal, false);
    }

}

void UEditView::DrawScene()
{
    GLint vertices[] = {0,   0,
                        300, 300,
                        300, 0};
    GLfloat colors[] = {1.0, 0.0, 0.0,
                        0.0, 1.0, 0.0,
                        0.0, 0.0, 1.0};
   
  
    
 
    glClearColor(1.0, 1.0, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);

    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);

    glColorPointer(3, GL_FLOAT, 0, colors);
    glVertexPointer(2, GL_INT, 0, vertices);

    glDrawArrays(GL_TRIANGLES, 0, 3);

 
    glColor3d(1.0, 0.0, 0.0);
  
 
    delete m_font;
    m_font = new Font("Arial", 120);
    m_font-&gt;print("hello", 10, 100);
    glFlush();
}

void UEditView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();
	CSize sizeTotal;
	// TODO: calculate the total size of this view
	sizeTotal.cx = sizeTotal.cy = 100;
	SetScrollSizes(MM_TEXT, sizeTotal);

}

// UEditView message handlers

int UEditView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CScrollView::OnCreate(lpCreateStruct) == -1)
        return -1;
  
  
    // describe and set the pixel format
    CClientDC dc(this);

    // fill in the pixel format descriptor
    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory(&pfd, sizeof pfd);
    pfd.nSize      = sizeof pfd;
    pfd.nVersion   = 1;

    // PFD_DOUBLEBUFFER   =&gt; allow OpenGL to do double buffering
    // PFD_SUPPORT_OPENGL =&gt; use OpenGL on this surface
    // PDF_DRAW_TO_WINDOW =&gt; draw to a window instead of a bitmap
    pfd.dwFlags    = PFD_DOUBLEBUFFER |
                     PFD_SUPPORT_OPENGL |
                     PFD_DRAW_TO_WINDOW;
    pfd.iPixelType = PFD_TYPE_RGBA;       // specify colors using (R, G, B, A) format
    pfd.cColorBits = 24;                  // bits per pixel

    // OpenGL maintains a buffer called the depth buffer
    // For each pixel, the depth buffer contains
    // the distance distance between the pixel and the viewer.
    // When OpenGL renders an object, it compares the position
    // of each new pixel to the position of the old pixel.  If
    // the position of the new pixel is closer, it is placed on to
    // the screen
    pfd.cDepthBits = 24;
    pfd.iLayerType = PFD_MAIN_PLANE;

    // compare generic pixel formats supported by window's NT and
    // hardware accelerators, returning the best match
    int pixelFormat = ChoosePixelFormat(dc.m_hDC, &pfd);
    if (pixelFormat == 0) 
    {
        TRACE("ChoosePixelFormat Failed %d
", GetLastError());
        return -1;
    }

    if (!SetPixelFormat(dc.m_hDC, pixelFormat, &pfd)) 
    {

        TRACE("SetPixelFormat Failed %d
", GetLastError());
        return -1;
    }

    // now that we have set the pixel format, we must create an
    // OpenGL rendering context(GLRC)
    // A rendering context is not the same thing as a device context, for
    // it includes information for OpenGL, while the device context includes
    // information for the GDI
    m_hrc = wglCreateContext(dc.m_hDC);
    if (!m_hrc) 
    {
        TRACE("wglCreateContext Failed %d
", GetLastError());
        return -1;
    }
    

    glShadeModel(GL_SMOOTH);

    // make m_hrc the current OpenGL rendering context
    if (!wglMakeCurrent(dc.m_hDC, m_hrc)) 
    {
        TRACE("wglMakeCurrent Failed%d
", GetLastError());      
        return FALSE;
    }

    SizeOpenGL(lpCreateStruct-&gt;cx, lpCreateStruct-&gt;cy);   

    return 0;
}

void UEditView::SizeOpenGL(GLint cx, GLint cy)
{
    CClientDC dc(this);

    // make m_hrc the current OpenGL rendering context
    if (!wglMakeCurrent(dc.m_hDC, m_hrc)) 
    {
        TRACE("wglMakeCurrent Failed%d
", GetLastError());      
        return;
    }

    // avoid divide by 0
    if (cy == 0) {
        cy = 1;
    }

    glViewport(0, 0, cx, cy);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

   // setup the OpenGL viewport
    GLdouble aspect = (GLdouble)cx/cy;
    gluOrtho2D(0.0, (GLdouble)cx, -100.0, (GLdouble)cy);

}

void UEditView::OnSize(UINT nType, int cx, int cy)
{
    CScrollView::OnSize(nType, cx, cy);

    CClientDC dc(this);

    // make m_hrc the current OpenGL rendering context
    if (!wglMakeCurrent(dc.m_hDC, m_hrc)) 
    {
        TRACE("wglMakeCurrent Failed%d
", GetLastError());      
        return;
    }

    SizeOpenGL(cx, cy);

}

BOOL UEditView::OnEraseBkgnd(CDC* pDC)
{
    return TRUE;
}

void UEditView::OnDestroy()
{
    CScrollView::OnDestroy();

    delete m_font;

    if (m_fullscreen) 
    {
        ToggleFullscreen();
    }

    wglMakeCurrent(NULL, NULL);

    if (m_hrc)
    {
        wglDeleteContext(m_hrc);
        m_hrc = NULL;
    }
}

void UEditView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
    m_active = bActivate;
    CScrollView::OnActivateView(bActivate, pActivateView, pDeactiveView);
 
}

void UEditView::ToggleFullscreen()
{

    CWnd* mainWnd = AfxGetMainWnd();
    CRect fullRect;

    if (!m_fullscreen) {
        mainWnd-&gt;GetWindowRect(&m_windowRect);

        GetDesktopWindow()-&gt;GetWindowRect(&fullRect);
     
        AdjustWindowRectEx(&fullRect, mainWnd-&gt;GetStyle(), FALSE, 
                           mainWnd-&gt;GetExStyle());
             
  
        mainWnd-&gt;MoveWindow(&fullRect);

        m_fullscreen = true;
    } else {
        m_fullscreen = false;
        mainWnd-&gt;MoveWindow(&m_windowRect);

    }
 

}

I also checked the return on wglUseFontBitmaps, and it returns false. GetLastError() returns 87 which means the parameter is incorrect.

I managed to get the font code to work with
code

void Font::BuildFont(HDC hdc, CFont& font)
{

    m_base = glGenLists(NUM_CHARACTER);

    CDC* dc;
    dc = CDC::FromHandle(hdc);

    CFont* oldFont = dc->SelectObject(&font);


    // build display list
    while (!wglUseFontBitmaps(hdc, 0, NUM_CHARACTER,
                      m_base) && GetLastError() == 87) 
    {

    }
    
    dc->SelectObject(oldFont);

}

It’s strange that wglUseBitmaps must be called multiple times like this though.