OpenGL & GDI mixing
От: LtS  
Дата: 30.04.02 08:37
Оценка:
Хочется работать по следующему сценарию:

/* 1) Отрисовать что-либо при помощи Win GDI */
DrawPreGL();
/* 2) Отрисовать что-либо при помощи OpenGL */
DrawOGL();
/* 3) Отрисовать что-либо при помощи Win GDI */
DrawPostGL();

SwapBuffers();

т.е. отрисовать до и после OpenGL при двойной буфферизации. Шаги 2 и 3 выполняются при этом хорошо, а вот шаг 1 совсем "забывается" после SwapBuffers, т.к. WinGDI рисует на front buffer.

Есть ли решения?
Re: OpenGL & GDI mixing
От: Sasparella США  
Дата: 30.04.02 15:08
Оценка: 3 (1)
Здравствуйте LtS, Вы писали:

1. это плохая идея, не стоит так делать
2. если все же решили — то копайте в сторону
glDrawBuffer(
  GLenum mode   
);



Саша.
Re[2]: OK
От: LtS  
Дата: 06.05.02 00:32
Оценка:
Спасибо за ответ,

S>1. это плохая идея, не стоит так делать

А какая идея будет получше, если хочется повыводить достаточно простыми методами с достаточным уровнем предсказуемости результатов двумерную графику совместно с трёхмерной. Хотябы текст как надо порисовать. У меня проект — кад и в в нём "маст би" много подписей-надписей-графики под и поверх 3D. Я не очень силён в OGL, потому может просто не знаю боль-мень дешевого пути.

Сейчас релизовано:

    pfd.dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL;
        SetPixelFormat( _hdc, m_GLPixelIndex, &pfd);


...и это даёт режим с полностью отсутствующим ускорением. :(
Re[3]: OK
От: Sasparella США  
Дата: 06.05.02 09:08
Оценка: 8 (1)
Здравствуйте LtS, Вы писали:

LtS> Спасибо за ответ,


S>>1. это плохая идея, не стоит так делать

LtS> А какая идея будет получше, если хочется повыводить достаточно простыми методами с достаточным уровнем предсказуемости результатов двумерную графику совместно с трёхмерной.

ПОнятно. У OpenGL точнее его куска под Windows есть чудесная функция wglBuildFontBitmaps.

Она по выбраному на данный момент в DC шрифту строит растровые изображения и кидает их в displayList-ы.

Потом ими можно очень просто выводить текст.

Вот привожу класс обертку для писания шрифтом в OpenGL


GLFont.h

// GLFont.h: interface for the CGLFont class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_GLFONT_H__563EFF12_A150_47EB_86C1_6F1E2B420978__INCLUDED_)
#define AFX_GLFONT_H__563EFF12_A150_47EB_86C1_6F1E2B420978__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <gl\gl.h>
#include <stdarg.h>        
#include "vector.hpp"

class CGLFont  
{
public:
    bool Print(const dvector dvPos, const char *fmt, ...);
    CSize GetTextSize(LPCTSTR pText);
    bool VerifyContext();
    bool Create(TCHAR* szFaceName = "Arial", int iHeight = -12, bool bBold=false, bool bItalic=false);
    bool KillFont();
    CGLFont();
    virtual ~CGLFont();
private:
    
    HGLRC m_hNativeGLRC;        // Holds HGLRC in which the font has been created
    HDC   m_hNativeDC;        // Holds HGLRC in which the font has been created
    bool m_bFontCreated;
    GLuint m_uiBase;
    HFONT m_hFont;

};

#endif // !defined(AFX_GLFONT_H__563EFF12_A150_47EB_86C1_6F1E2B420978__INCLUDED_)


// GLFont.cpp: implementation of the CGLFont class.
//
//    Purpose: OpenGL raster font wrapper
//    Author:    Alexander Bijamov aka Sasparella
//    Created: N/A
//    
//    Last Modified: 10 April 2002              by A. Bijamov.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "GLFont.h"
#include "OpenGL.h"
#include "routines.h"
#include <gl\gl.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define NUM_CHARACTERS 96

CGLFont::CGLFont()
{
    m_hNativeGLRC = NULL;
    m_hNativeDC = NULL;
    m_bFontCreated = false;
    m_hFont = NULL;
}

CGLFont::~CGLFont()
{
    KillFont();
}

bool CGLFont::Create(TCHAR *szFaceName, int iHeight, bool bBold, bool bItalic)
{    

    if (m_bFontCreated && (!KillFont())) return false; // could not kill font - probably different context

    HDC hDC = ::wglGetCurrentDC();
    if (!hDC) return false;
    
    m_hFont = CreateFont(iHeight,
                        0,                                // Width Of Font
                        0,                                // Angle Of Escapement
                        0,                                // Orientation Angle
                        bBold? FW_BOLD:FW_NORMAL,        // Font Weight
                        bItalic,                        // Italic
                        FALSE,                            // Underline
                        FALSE,                            // Strikeout
                        ANSI_CHARSET,                    // Character Set Identifier
                        OUT_TT_PRECIS,                    // Output Precision
                        CLIP_DEFAULT_PRECIS,            // Clipping Precision
                        ANTIALIASED_QUALITY,            // Output Quality
                        FF_DONTCARE|DEFAULT_PITCH,        // Family And Pitch
                        szFaceName);                    // Font Name

    if (!m_hFont)
    {
        DisplayErrorMessage("CreateFont");
        return false;
    }

    m_uiBase = glGenLists(NUM_CHARACTERS);

    HFONT hOldFnt = (HFONT)SelectObject(hDC, (HGDIOBJ)m_hFont);    // Selects The Font We Want
    

    VERIFY(wglUseFontBitmaps(hDC, 32, NUM_CHARACTERS, m_uiBase));                // Builds 96 Characters Starting At Character 32
    
    glFlush();

    SelectObject(hDC, (HGDIOBJ)hOldFnt);
    

    m_hNativeGLRC = :: wglGetCurrentContext();
    m_hNativeDC   = hDC;
    m_bFontCreated = true;
    return true;
}

bool CGLFont::KillFont()
{
    //if (!VerifyContext()) return false; // you try to kill font, but you did not create it...
    if (!m_bFontCreated) return false;
    CToggleContext tc(m_hNativeDC, m_hNativeGLRC);
    ASSERT(::wglGetCurrentContext());

    glDeleteLists(m_uiBase, NUM_CHARACTERS);    
    DeleteObject(m_hFont);
    m_bFontCreated = false;
    return true;
}

bool CGLFont::VerifyContext()
{
    return (m_bFontCreated && ::wglGetCurrentContext()==m_hNativeGLRC && ::wglGetCurrentDC()==m_hNativeDC );
}

CSize CGLFont::GetTextSize(LPCTSTR pText)
{
    if (!m_bFontCreated) return CSize(0,0);
    
    HFONT hOldFnt = (HFONT)SelectObject(m_hNativeDC, (HGDIOBJ)m_hFont);    
    
    CDC* pDC = CDC::FromHandle(m_hNativeDC);
    CSize size = pDC->GetTextExtent(CString(pText));
    SelectObject(m_hNativeDC, (HGDIOBJ)hOldFnt);    

    return size;
}

bool CGLFont::Print(const dvector dvPos, const char *fmt, ...)        
{
    if (!VerifyContext()) return false;

    char        text[256];                            
    va_list        ap;                                    

    if (fmt == NULL)                                    
        return true;

    va_start(ap, fmt);
        vsprintf(text, fmt, ap);
    va_end(ap);

    glRasterPos3d(dvPos.x,dvPos.y,dvPos.z);

    glPushAttrib(GL_LIST_BIT);
    glListBase(m_uiBase - 32);
    
    glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
    
    glPopAttrib();
    return true;
}



и вспомогательный клсаа


class CToggleContext
{
public:
    ~CToggleContext();
    CToggleContext(HDC hDC, HGLRC hGLRC);
private:
    HGLRC m_hMemoGLRC;
    HDC m_hMemoDC;
};

CToggleContext::CToggleContext(HDC hDC, HGLRC hGLRC)
{
    m_hMemoDC = wglGetCurrentDC();
    m_hMemoGLRC = wglGetCurrentContext();

    if (!wglMakeCurrent(hDC,hGLRC)) 
        DisplayErrorMessage("MakeCurrent");
}


CToggleContext::~CToggleContext()
{
    if (!wglMakeCurrent(m_hMemoDC,m_hMemoGLRC)) DisplayErrorMessage("MakeCurrent");
}


Кажись все понятно должно быть.


В классе вашего OpenGL окна созда5ете CGLfont glFont;

в инициализации после инита контекста вызываете glFont.Create(....)

а в очистке — glFont.KillFont() (до убивания контекста)



Рисовать —
glFont.Print(const dvector dvPos, const char *fmt, ...);

dvPos — это обычные координаты, как у glVertex. В этом месте и будет выведен текси.


Enjoy.


Саша.
Re[4]: OK
От: LtS  
Дата: 07.05.02 01:11
Оценка:
Большое спасибо! &

...ну тогда ещё один навера последний вопрос: как толком рисовать в OGL не разбираясь с 3D?

Наверна надо будет сказать glDisable(GL_DEPTH_TEST), для начала. А потом хотелось бы, чтобы во всех проекциях например нарисовалась линия из (0,0) в (100, 100). Вообще говоря настройка матриц — не самый плохой вариант, но может есть что-то более прогрессивное и главное простое?
Re[5]: OK
От: Sasparella США  
Дата: 07.05.02 04:49
Оценка: 3 (1)
Здравствуйте LtS, Вы писали:

LtS>Большое спасибо! &


LtS>...ну тогда ещё один навера последний вопрос: как толком рисовать в OGL не разбираясь с 3D?


LtS>Наверна надо будет сказать glDisable(GL_DEPTH_TEST), для начала. А потом хотелось бы, чтобы во всех проекциях например нарисовалась линия из (0,0) в (100, 100). Вообще говоря настройка матриц — не самый плохой вариант, но может есть что-то более прогрессивное и главное простое?


Ну куда уж прогрессивнее и проще, чем пару матриц настроитть!

Ок, без проблем. Можно настроить матрицы преобразования так, чтобы рисовать прямо в "оконных" координатах. Конкретно:


Here is code to configure OpenGL for a 2D window coordinate system with an upper left-hand origin where w and h are the window&acirc;s width and height in pixels:

glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, w, h, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 
Note that the bottom and top parameters (the 3rd and 4th parameters) to glOrtho specify the window height as the top and zero as the bottom. This flips the origin to put the origin at the window&acirc;s upper left-hand corner.

Now, you can safely set the raster position at a pixel position in window coordinates like this

glVertex2i(x, y);
glRasterPos2i(x, y);


Кстати — вот статья, откуда взят сей текст:Avoiding 16 Common OpenGL Pitfalls.

Стаься во многих смыслах полезная, и избавляющая от многих часов битья головой об стену...


А OpenGL между прочим содержит ф-ии типа glVertex2d — то есть 2d — это его частный случай. Но все равно настраивать нужно как для 3д, — просто как будто сверху смотрим на лист фанеры....


Удачи.

Саша.
Re[6]: OK
От: Юнусов Булат Россия  
Дата: 07.05.02 09:41
Оценка:
Здравствуйте Sasparella, Вы писали:


S>glViewport(0, 0, w, h);

S>glMatrixMode(GL_PROJECTION);
S>glLoadIdentity();
S>glOrtho(0, w, h, 0, -1, 1);
S>glMatrixMode(GL_MODELVIEW);
S>glLoadIdentity();

Сравнил со своим текущим проектом
void CVcmTestView::OnSize(UINT nType, int cx, int cy) 
{
    CView::OnSize(nType, cx, cy);
    
    // TODO: Add your message handler code here
    CRect r;
    GetClientRect(&r);
    m_width = r.Width();
    m_height = r.Height();
    
    ::glViewport(0, 0, m_width, m_height);
    ::glMatrixMode(GL_PROJECTION);
    ::glLoadIdentity();
    ::glOrtho(0, m_width, 0, m_height, 0, m_depth);
    ::glMatrixMode(GL_MODELVIEW);
}
Re[7]: OK
От: Sasparella США  
Дата: 07.05.02 13:53
Оценка: 1 (1)
Здравствуйте Юнусов Булат, Вы писали:

ЮБ>Здравствуйте Sasparella, Вы писали:


ЮБ>Сравнил со своим текущим проектом

ЮБ>
ЮБ>void CVcmTestView::OnSize(UINT nType, int cx, int cy) 
ЮБ>{
ЮБ>    CView::OnSize(nType, cx, cy);
ЮБ>    
ЮБ>    // TODO: Add your message handler code here
ЮБ>    CRect r;
ЮБ>    GetClientRect(&r);
ЮБ>    m_width = r.Width();
ЮБ>    m_height = r.Height();
ЮБ>    
ЮБ>    ::glViewport(0, 0, m_width, m_height);
ЮБ>    ::glMatrixMode(GL_PROJECTION);
ЮБ>    ::glLoadIdentity();
ЮБ>    ::glOrtho(0, m_width, 0, m_height, 0, m_depth);
ЮБ>    ::glMatrixMode(GL_MODELVIEW);
ЮБ>}
ЮБ>




а где wglMakeCurrent()? или вы его при создании делаете текущим и на всю жизнь? ИМНО лучше все таки делать его текущим только когда надо.


Саша.
Re[6]: :)
От: LtS  
Дата: 08.05.02 04:10
Оценка:
...пасибки! Частично перевёл код на OGL. Головой обычно я правда не бьюсь — это для любителей искуства всё же. Обычно на такое не хватает времени. Сейчас начал прилизывать проектец и вот началось всякое...

...будем копать!
Re[4]: ...вывод текста
От: LtS  
Дата: 10.05.02 06:14
Оценка:
...итак, последнее что осталось от Win GDI это вывод текста. Как и следовало предполагать указанный способ не позволяет выводить текст под каким-либо углом кроме простого горизонтального положения.

Попытка воспользоваться

    wglUseFontOutlines(dc, '0', 10, fBase, 0.0f, 0/*0.15f*/, WGL_FONT_POLYGONS, 0);

пока ещё не привела к успеху. Отчего-то простая замена на


    wglUseFontBitmaps(dc, '0', 10, fBase);

даёт превосходные результаты, но... с ограниченной функциональностью.


glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

glColor3f(1.0, 0, 0);
    glPushAttrib(GL_LIST_BIT);
    glListBase(fBase-'0');
    
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
    glScalef(30,30,0);
    glTranslatef(100,100,0);
    glCallList('0');
glPopMatrix();
glPopAttrib();

...казалось бы всё правильно, но не работает.
Re[5]: ...вывод текста
От: Sasparella США  
Дата: 10.05.02 17:55
Оценка:
Здравствуйте LtS, Вы писали:


LtS>...казалось бы всё правильно, но не работает.


Нет. не совсем. Дел в том, что матрицы преобразований действую на позицию вывода растра, соответствующего букве, а не на сам растр.

Я не пробовал писать повернутым шрифтом, но могу сфолрмулироват ьнесколько фактов, возмжно могущим вам помоч.


1. Такой фокус точно пройдет c wglFontOutlines, но испольнозать их дорого.
2. Текст пишется, (а не происходит вывод букв друг на друге) так как вывод Bitmap-а сдвигает текущую позиуию растра. По умолчанию — вправо на свой размер. Этим кажется можно управлять — и заставить его смещать его вниз. Тогда текст будет писаться вертикально.
3. Повернутые буквы можно получить посторив битмепы по соотв созданному повернутому шрифту (не пробовал — но не вижу причин почему не должно работать)

Вот.


Саша.
Re[6]: ...вывод текста
От: LtS  
Дата: 10.05.02 23:31
Оценка:
Проблемка решилась! Сёдня выдали снап и по ходу проект доведён до некотого эпапа когда можно отдохнуть.

S>1. Такой фокус точно пройдет c wglFontOutlines, но испольнозать их дорого.

Именно так и решил. В моём случае это приемлемые расходы и пойти на них — это дёшево.

проблема в использовании этой функции была в том, что получающаяся надпись был ОЧЕНЬ маленького размера (меньше точки). Всякие GetTextExpPoint32 отдохнули по полной программе (пришлось написать свою такую функцию).
В общем в результате я получил-таки полностью аппаратно ускоренный код, который и был отправлен на тестирование.

S>2. Текст пишется, (а не происходит вывод букв друг на друге) так как вывод Bitmap-а сдвигает текущую позиуию растра. По умолчанию — вправо на свой размер. Этим кажется можно управлять — и заставить его смещать его вниз. Тогда текст будет писаться вертикально.

...да, но буквы (в моём случае цифры) будут всё же с традиционной ориентацией.

S>3. Повернутые буквы можно получить посторив битмепы по соотв созданному повернутому шрифту (не пробовал — но не вижу причин почему не должно работать)

...пожалуй, что да, но это пока для меня сложновато, опять-таки просто не до того было.

Андрей.
Re[8]: OK
От: Юнусов Булат Россия  
Дата: 14.05.02 08:15
Оценка:
Здравствуйте Sasparella, Вы писали:

S>а где wglMakeCurrent()? или вы его при создании делаете текущим и на всю жизнь? ИМНО лучше все таки делать его текущим только когда надо.


Сорри, что долго не отвечал — пока безлошадный.
Угу, делаю один раз в OnCreate. А что, так не принято? Если да то чем чревато?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.