add oversampler
This commit is contained in:
264
oversampling/WDL/lice/lice_gl_ctx.cpp
Normal file
264
oversampling/WDL/lice/lice_gl_ctx.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
#include "lice_gl_ctx.h"
|
||||
|
||||
#define MAX_CACHED_GLYPHS 4096
|
||||
|
||||
// create one hidden window per process to hold the openGL state,
|
||||
// its GL render context stays current for the life of the process,
|
||||
// we serve all framebuffers from the same render context
|
||||
|
||||
class LICE_GL_ctx
|
||||
{
|
||||
public:
|
||||
|
||||
LICE_GL_ctx();
|
||||
~LICE_GL_ctx();
|
||||
|
||||
bool IsValid();
|
||||
HWND GetWindow() { return m_hwnd; }
|
||||
void Close();
|
||||
|
||||
GLUnurbsObj* GetNurbsObj(int linetol=8); // linetol = maximum number of straight-line pixels
|
||||
|
||||
int GetTexFromGlyph(const unsigned char* glyph, int glyph_w, int glyph_h);
|
||||
void ClearTex();
|
||||
|
||||
struct GlyphCache
|
||||
{
|
||||
unsigned int tex;
|
||||
unsigned char* glyph; // lives on the heap
|
||||
int glyph_w, glyph_h;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
bool Init();
|
||||
|
||||
bool m_init_tried;
|
||||
HINSTANCE m_gldll;
|
||||
HWND m_hwnd;
|
||||
HGLRC m_glrc;
|
||||
|
||||
GLUnurbsObj* m_nurbs; // keep this here for easy reuse
|
||||
|
||||
GlyphCache m_glyphCache[MAX_CACHED_GLYPHS];
|
||||
int m_nCachedGlyphs;
|
||||
};
|
||||
|
||||
LICE_GL_ctx::LICE_GL_ctx()
|
||||
{
|
||||
m_init_tried = false;
|
||||
m_gldll = 0;
|
||||
m_hwnd = 0;
|
||||
m_glrc = 0;
|
||||
m_nurbs = 0;
|
||||
memset(m_glyphCache, 0, MAX_CACHED_GLYPHS*sizeof(GlyphCache));
|
||||
m_nCachedGlyphs = 0;
|
||||
}
|
||||
|
||||
LICE_GL_ctx::~LICE_GL_ctx()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool LICE_GL_ctx::Init()
|
||||
{
|
||||
m_init_tried = true;
|
||||
|
||||
m_gldll = LoadLibrary("opengl32.dll");
|
||||
if (!m_gldll)
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// create a minimal GL render context to serve FBOs out of
|
||||
WNDCLASS wc;
|
||||
memset(&wc, 0, sizeof(WNDCLASS));
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = DefWindowProc;
|
||||
wc.lpszClassName = "LICE_GL_ctx";
|
||||
RegisterClass(&wc);
|
||||
m_hwnd = CreateWindow("LICE_GL_ctx", "LICE_GL_ctx", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0);
|
||||
HDC dc = GetDC(m_hwnd);
|
||||
if (!dc)
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 24;
|
||||
pfd.cAlphaBits = 8;
|
||||
int pxfmt = ChoosePixelFormat(dc, &pfd);
|
||||
if (!SetPixelFormat(dc, pxfmt, &pfd))
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_glrc = wglCreateContext(dc);
|
||||
if (!wglMakeCurrent(dc, m_glrc)) // render context should stay current throughout
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
char *rendstr = (char*) glGetString(GL_RENDERER);
|
||||
if (!rendstr || strstr(rendstr, "GDI"))
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// check now for all the extension functions we will ever need
|
||||
if (glewInit() != GLEW_OK ||
|
||||
!glewIsSupported("GL_EXT_framebuffer_object") ||
|
||||
!glewIsSupported("GL_ARB_texture_rectangle"))
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// any one-time initialization goes here
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
ReleaseDC(m_hwnd, dc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LICE_GL_ctx::IsValid()
|
||||
{
|
||||
if (m_gldll && m_glrc) return true;
|
||||
if (!m_init_tried) return Init();
|
||||
return false;
|
||||
}
|
||||
|
||||
void LICE_GL_ctx::Close()
|
||||
{
|
||||
ClearTex();
|
||||
if (m_nurbs)
|
||||
{
|
||||
gluDeleteNurbsRenderer(m_nurbs);
|
||||
m_nurbs = 0;
|
||||
}
|
||||
if (m_glrc)
|
||||
{
|
||||
wglMakeCurrent(0, 0);
|
||||
wglDeleteContext(m_glrc);
|
||||
m_glrc = 0;
|
||||
}
|
||||
if (m_hwnd)
|
||||
{
|
||||
DestroyWindow(m_hwnd);
|
||||
m_hwnd = 0;
|
||||
}
|
||||
if (m_gldll)
|
||||
{
|
||||
FreeLibrary(m_gldll);
|
||||
m_gldll = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GLUnurbsObj* LICE_GL_ctx::GetNurbsObj(int linetol)
|
||||
{
|
||||
if (!IsValid()) return 0;
|
||||
if (!m_nurbs) m_nurbs = gluNewNurbsRenderer();
|
||||
if (m_nurbs) gluNurbsProperty(m_nurbs, GLU_SAMPLING_TOLERANCE, (float)linetol);
|
||||
return m_nurbs;
|
||||
}
|
||||
|
||||
void LICE_GL_ctx::ClearTex()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < m_nCachedGlyphs; ++i)
|
||||
{
|
||||
glDeleteTextures(1, &m_glyphCache[i].tex);
|
||||
free(m_glyphCache[i].glyph);
|
||||
memset(&m_glyphCache[i], 0, sizeof(GlyphCache));
|
||||
}
|
||||
m_nCachedGlyphs = 0;
|
||||
}
|
||||
|
||||
static int _glyphcmp(const void* p1, const void* p2)
|
||||
{
|
||||
LICE_GL_ctx::GlyphCache* gc1 = (LICE_GL_ctx::GlyphCache*) p1;
|
||||
LICE_GL_ctx::GlyphCache* gc2 = (LICE_GL_ctx::GlyphCache*) p2;
|
||||
|
||||
if (gc1->glyph_w < gc2->glyph_w) return -1;
|
||||
if (gc1->glyph_w > gc2->glyph_w) return 1;
|
||||
if (gc1->glyph_h < gc2->glyph_h) return -1;
|
||||
if (gc1->glyph_h > gc2->glyph_h) return 1;
|
||||
return memcmp(gc1->glyph, gc2->glyph, gc1->glyph_w*gc1->glyph_h);
|
||||
}
|
||||
|
||||
int LICE_GL_ctx::GetTexFromGlyph(const unsigned char* glyph, int glyph_w, int glyph_h)
|
||||
{
|
||||
if (!IsValid()) return false;
|
||||
|
||||
GlyphCache gc;
|
||||
gc.tex = 0;
|
||||
gc.glyph = (unsigned char *)glyph;
|
||||
gc.glyph_w = glyph_w;
|
||||
gc.glyph_h = glyph_h;
|
||||
|
||||
GlyphCache* p = (GlyphCache*) bsearch(&gc, m_glyphCache, m_nCachedGlyphs, sizeof(GlyphCache), _glyphcmp);
|
||||
if (p) return p->tex;
|
||||
|
||||
glGenTextures(1, &gc.tex);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, gc.tex);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA8, glyph_w, glyph_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, glyph);
|
||||
|
||||
if (m_nCachedGlyphs >= MAX_CACHED_GLYPHS) ClearTex(); // quick & dirty
|
||||
|
||||
gc.glyph = (unsigned char*) malloc(glyph_w*glyph_h);
|
||||
memcpy(gc.glyph, glyph, glyph_w*glyph_h);
|
||||
m_glyphCache[m_nCachedGlyphs++] = gc; // copy
|
||||
qsort(m_glyphCache, m_nCachedGlyphs, sizeof(GlyphCache), _glyphcmp);
|
||||
|
||||
return gc.tex;
|
||||
}
|
||||
|
||||
////////
|
||||
|
||||
static LICE_GL_ctx s_glctx; // one static opengl context object per process
|
||||
|
||||
|
||||
bool LICE_GL_IsValid()
|
||||
{
|
||||
return s_glctx.IsValid();
|
||||
}
|
||||
|
||||
HWND LICE_GL_GetWindow()
|
||||
{
|
||||
if (s_glctx.IsValid()) return s_glctx.GetWindow();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LICE_GL_CloseCtx()
|
||||
{
|
||||
s_glctx.Close();
|
||||
}
|
||||
|
||||
GLUnurbsObj* LICE_GL_GetNurbsObj(int linetol) // linetol = maximum number of straight-line pixels
|
||||
{
|
||||
return s_glctx.GetNurbsObj(linetol);
|
||||
}
|
||||
|
||||
GLuint LICE_GL_GetTexFromGlyph(const unsigned char* glyph, int glyph_w, int glyph_h)
|
||||
{
|
||||
return s_glctx.GetTexFromGlyph(glyph, glyph_w, glyph_h);
|
||||
}
|
||||
|
||||
void LICE_GL_ClearTex()
|
||||
{
|
||||
s_glctx.ClearTex();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user