add oversampler

This commit is contained in:
2024-05-24 13:28:31 +02:00
parent e4a4a661a0
commit 989dba5a6b
484 changed files with 313937 additions and 0 deletions

View 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();
}