1 #include "lice_gl_ctx.h"
3 #define MAX_CACHED_GLYPHS 4096
5 // create one hidden window per process to hold the openGL state,
6 // its GL render context stays current for the life of the process,
7 // we serve all framebuffers from the same render context
17 HWND
GetWindow() { return m_hwnd
; }
20 GLUnurbsObj
* GetNurbsObj(int linetol
=8); // linetol = maximum number of straight-line pixels
22 int GetTexFromGlyph(const unsigned char* glyph
, int glyph_w
, int glyph_h
);
28 unsigned char* glyph
; // lives on the heap
41 GLUnurbsObj
* m_nurbs
; // keep this here for easy reuse
43 GlyphCache m_glyphCache
[MAX_CACHED_GLYPHS
];
47 LICE_GL_ctx::LICE_GL_ctx()
54 memset(m_glyphCache
, 0, MAX_CACHED_GLYPHS
*sizeof(GlyphCache
));
58 LICE_GL_ctx::~LICE_GL_ctx()
63 bool LICE_GL_ctx::Init()
67 m_gldll
= LoadLibrary("opengl32.dll");
74 // create a minimal GL render context to serve FBOs out of
76 memset(&wc
, 0, sizeof(WNDCLASS
));
77 wc
.hInstance
= GetModuleHandle(0);
78 wc
.lpfnWndProc
= DefWindowProc
;
79 wc
.lpszClassName
= "LICE_GL_ctx";
81 m_hwnd
= CreateWindow("LICE_GL_ctx", "LICE_GL_ctx", 0, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, 0, 0, GetModuleHandle(0), 0);
82 HDC dc
= GetDC(m_hwnd
);
89 PIXELFORMATDESCRIPTOR pfd
;
90 memset(&pfd
, 0, sizeof(PIXELFORMATDESCRIPTOR
));
91 pfd
.nSize
= sizeof(PIXELFORMATDESCRIPTOR
);
93 pfd
.dwFlags
= PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
;
94 pfd
.iPixelType
= PFD_TYPE_RGBA
;
97 int pxfmt
= ChoosePixelFormat(dc
, &pfd
);
98 if (!SetPixelFormat(dc
, pxfmt
, &pfd
))
104 m_glrc
= wglCreateContext(dc
);
105 if (!wglMakeCurrent(dc
, m_glrc
)) // render context should stay current throughout
111 char *rendstr
= (char*) glGetString(GL_RENDERER
);
112 if (!rendstr
|| strstr(rendstr
, "GDI"))
118 // check now for all the extension functions we will ever need
119 if (glewInit() != GLEW_OK
||
120 !glewIsSupported("GL_EXT_framebuffer_object") ||
121 !glewIsSupported("GL_ARB_texture_rectangle"))
127 // any one-time initialization goes here
128 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
130 ReleaseDC(m_hwnd
, dc
);
135 bool LICE_GL_ctx::IsValid()
137 if (m_gldll
&& m_glrc
) return true;
138 if (!m_init_tried
) return Init();
142 void LICE_GL_ctx::Close()
147 gluDeleteNurbsRenderer(m_nurbs
);
152 wglMakeCurrent(0, 0);
153 wglDeleteContext(m_glrc
);
158 DestroyWindow(m_hwnd
);
163 FreeLibrary(m_gldll
);
168 GLUnurbsObj
* LICE_GL_ctx::GetNurbsObj(int linetol
)
170 if (!IsValid()) return 0;
171 if (!m_nurbs
) m_nurbs
= gluNewNurbsRenderer();
172 if (m_nurbs
) gluNurbsProperty(m_nurbs
, GLU_SAMPLING_TOLERANCE
, (float)linetol
);
176 void LICE_GL_ctx::ClearTex()
179 for (i
= 0; i
< m_nCachedGlyphs
; ++i
)
181 glDeleteTextures(1, &m_glyphCache
[i
].tex
);
182 free(m_glyphCache
[i
].glyph
);
183 memset(&m_glyphCache
[i
], 0, sizeof(GlyphCache
));
188 static int _glyphcmp(const void* p1
, const void* p2
)
190 LICE_GL_ctx::GlyphCache
* gc1
= (LICE_GL_ctx::GlyphCache
*) p1
;
191 LICE_GL_ctx::GlyphCache
* gc2
= (LICE_GL_ctx::GlyphCache
*) p2
;
193 if (gc1
->glyph_w
< gc2
->glyph_w
) return -1;
194 if (gc1
->glyph_w
> gc2
->glyph_w
) return 1;
195 if (gc1
->glyph_h
< gc2
->glyph_h
) return -1;
196 if (gc1
->glyph_h
> gc2
->glyph_h
) return 1;
197 return memcmp(gc1
->glyph
, gc2
->glyph
, gc1
->glyph_w
*gc1
->glyph_h
);
200 int LICE_GL_ctx::GetTexFromGlyph(const unsigned char* glyph
, int glyph_w
, int glyph_h
)
202 if (!IsValid()) return false;
206 gc
.glyph
= (unsigned char *)glyph
;
207 gc
.glyph_w
= glyph_w
;
208 gc
.glyph_h
= glyph_h
;
210 GlyphCache
* p
= (GlyphCache
*) bsearch(&gc
, m_glyphCache
, m_nCachedGlyphs
, sizeof(GlyphCache
), _glyphcmp
);
211 if (p
) return p
->tex
;
213 glGenTextures(1, &gc
.tex
);
214 glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, gc
.tex
);
215 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
216 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
217 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB
, 0, GL_ALPHA8
, glyph_w
, glyph_h
, 0, GL_ALPHA
, GL_UNSIGNED_BYTE
, glyph
);
219 if (m_nCachedGlyphs
>= MAX_CACHED_GLYPHS
) ClearTex(); // quick & dirty
221 gc
.glyph
= (unsigned char*) malloc(glyph_w
*glyph_h
);
222 memcpy(gc
.glyph
, glyph
, glyph_w
*glyph_h
);
223 m_glyphCache
[m_nCachedGlyphs
++] = gc
; // copy
224 qsort(m_glyphCache
, m_nCachedGlyphs
, sizeof(GlyphCache
), _glyphcmp
);
231 static LICE_GL_ctx s_glctx
; // one static opengl context object per process
234 bool LICE_GL_IsValid()
236 return s_glctx
.IsValid();
239 HWND
LICE_GL_GetWindow()
241 if (s_glctx
.IsValid()) return s_glctx
.GetWindow();
245 void LICE_GL_CloseCtx()
250 GLUnurbsObj
* LICE_GL_GetNurbsObj(int linetol
) // linetol = maximum number of straight-line pixels
252 return s_glctx
.GetNurbsObj(linetol
);
255 GLuint
LICE_GL_GetTexFromGlyph(const unsigned char* glyph
, int glyph_w
, int glyph_h
)
257 return s_glctx
.GetTexFromGlyph(glyph
, glyph_w
, glyph_h
);
260 void LICE_GL_ClearTex()