2013-07-18 2 views
2

Я пытаюсь сделать текст в OpenGL, это то, как я это делаю:Странное поведение в OpenGL

  • чтения пикселов растрового изображения с помощью glReadPixels и SetDIBits;
  • нарисовать текст на растровом изображении с использованием холста;
  • рисовать пиксели в буфер основной рамки, используя GetDIBits и glDrawPixels.

Это то, что я получаю, когда оказываю Sample text (81x21).

"Sample text"

растровое изображение.

"Sample text" bitmap

Это то, что я получаю, когда я вынести Sample text. (84x21) (с точкой в ​​конце).

"Sample text."

"Sample text." bitmap

Он работает. Он всегда работает, когда результирующая ширина текста равна двум! Strange ...
Это код.

procedure TMainForm.RenderBtnClick(Sender: TObject); 
var 
    DC, RC: HDC; 
    BMP: TBitmap; 
    Pixels: Pointer; 
    X, Y, W, H: Integer; 
    Header: PBitmapInfo; 
    Result, Error: Integer; 
    Str: String; 
begin 
    // Initialize OpenGL 
    if InitOpenGL = False then 
    Application.Terminate; 
    DC := GetDC(Handle); 
    RC := CreateRenderingContext(DC, 
           [OpDoubleBuffered], 
           32, 
           24, 
           0, 
           0, 
           0, 
           0); 
    ActivateRenderingContext(DC, RC); 
    Caption := 
    'OpenGL version: ' + glGetString(GL_VERSION) + ' | ' + 
    'vendor: '   + glGetString(GL_VENDOR) + ' | ' + 
    'renderer: '  + glGetString(GL_RENDERER); 

    // Setup OpenGL 
    glClearColor(0.27, 0.4, 0.7, 0.0); // Light blue 
    glViewport(0, 0, ClientWidth, ClientHeight); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity; 
    glOrtho(0, ClientWidth, 0, ClientHeight, 0, 1); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity; 
    glClear(GL_COLOR_BUFFER_BIT); 

    BMP := TBitmap.Create; 
    BMP.PixelFormat := pf24bit; 
    BMP.Canvas.Font.Name := 'Segoe UI'; 
    BMP.Canvas.Font.Size := 12; 
    BMP.Canvas.Font.Color := clWhite; 
    BMP.Canvas.Brush.Style := bsClear; 
    Str := Edit.Text; 
    W := BMP.Canvas.TextWidth(Str); 
    H := BMP.Canvas.TextHeight(Str); 
    X := (ClientWidth - W) div 2; 
    Y := (ClientHeight - H) div 2; 
    BMP.Width := W; 
    BMP.Height := H; 

    GetMem(Pixels, W * H * 3); 
    GetMem(Header, SizeOf(TBitmapInfoHeader)); 
    with Header^.bmiHeader do 
    begin 
    biSize := SizeOf(TBitmapInfoHeader); 
    biWidth := W; 
    biHeight := H; 
    biCompression := BI_RGB; 
    biPlanes := 1; 
    biBitCount := 24; 
    biSizeImage := W * H * 3; 
    end; 

    glReadPixels(X, Y, W, H, GL_BGR, GL_UNSIGNED_BYTE, Pixels); 
    Result := SetDIBits(BMP.Canvas.Handle, BMP.Handle, 0, H, Pixels, 
    TBitmapInfo(Header^), DIB_RGB_COLORS); 
    if Result = 0 then 
    begin 
    Error := GetLastError; 
    raise Exception.Create('"SetDIBits" error ' + IntToStr(Error) + ': ' + SysErrorMessage(Error)); 
    end; 

    BMP.Canvas.TextOut(0, 0, Str); 
    BMP.SaveToFile('C:/TextOut.bmp'); // for debugging purposes of course 

    Result := GetDIBits(BMP.Canvas.Handle, BMP.Handle, 0, H, Pixels, TBitmapInfo(Header^), DIB_RGB_COLORS); 
    if Result = 0 then 
    begin 
    Error := GetLastError; 
    raise Exception.Create('"GetDIBits" error ' + IntToStr(Error) + ': ' + SysErrorMessage(Error)); 
    end; 

    glRasterPos2i(X, Y); 
    glDrawPixels(W, H, GL_BGR, GL_UNSIGNED_BYTE, Pixels); 
    SwapBuffers(DC); 

    // Free memory 
    DeactivateRenderingContext; 
    wglDeleteContext(RC); 
    ReleaseDC(Handle, DC); 
    FreeMem(Header); 
    FreeMem(Pixels); 
    BMP.Free; 
end; 

я дважды проверил код с glGetError - без ошибок. Я видел много сообщений о нечетном поведении с SetDIBits и его производными. Некоторые утверждают, что странность имеет отношение к управлению памятью Delphi, но у меня есть сомнения. Любые идеи, что я могу попробовать дальше?

Редактировать: он работает, если я использую альфа.

ответ

3

Необходимо учитывать выравнивание. По умолчанию GL ожидает выравнивание по 4 байта для каждой строки изображения. Asy вы используете 3 байта на пиксель, может быть что угодно, в зависимости от ширины. Посмотрите на glPixelStore(), чтобы изменить выравнивание. Особенно полезно установить GL_PACK_ALIGNMENT (для чтения пикселей из GL) и GL_UNPACK_ALIGNMENT (для отправки пикселей в GL) до 1 для вашего прецедента.

Смежные вопросы