merging cockos wdl
[wdl/wdl-ol.git] / WDL / lice / lice_gl_ctx.cpp
blob1a91f5f6adad00092290b0c671966270f93f2742
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
9 class LICE_GL_ctx
11 public:
13 LICE_GL_ctx();
14 ~LICE_GL_ctx();
16 bool IsValid();
17 HWND GetWindow() { return m_hwnd; }
18 void Close();
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);
23 void ClearTex();
25 struct GlyphCache
27 unsigned int tex;
28 unsigned char* glyph; // lives on the heap
29 int glyph_w, glyph_h;
32 private:
34 bool Init();
36 bool m_init_tried;
37 HINSTANCE m_gldll;
38 HWND m_hwnd;
39 HGLRC m_glrc;
41 GLUnurbsObj* m_nurbs; // keep this here for easy reuse
43 GlyphCache m_glyphCache[MAX_CACHED_GLYPHS];
44 int m_nCachedGlyphs;
47 LICE_GL_ctx::LICE_GL_ctx()
49 m_init_tried = false;
50 m_gldll = 0;
51 m_hwnd = 0;
52 m_glrc = 0;
53 m_nurbs = 0;
54 memset(m_glyphCache, 0, MAX_CACHED_GLYPHS*sizeof(GlyphCache));
55 m_nCachedGlyphs = 0;
58 LICE_GL_ctx::~LICE_GL_ctx()
60 Close();
63 bool LICE_GL_ctx::Init()
65 m_init_tried = true;
67 m_gldll = LoadLibrary("opengl32.dll");
68 if (!m_gldll)
70 Close();
71 return false;
74 // create a minimal GL render context to serve FBOs out of
75 WNDCLASS wc;
76 memset(&wc, 0, sizeof(WNDCLASS));
77 wc.hInstance = GetModuleHandle(0);
78 wc.lpfnWndProc = DefWindowProc;
79 wc.lpszClassName = "LICE_GL_ctx";
80 RegisterClass(&wc);
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);
83 if (!dc)
85 Close();
86 return false;
89 PIXELFORMATDESCRIPTOR pfd;
90 memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
91 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
92 pfd.nVersion = 1;
93 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
94 pfd.iPixelType = PFD_TYPE_RGBA;
95 pfd.cColorBits = 24;
96 pfd.cAlphaBits = 8;
97 int pxfmt = ChoosePixelFormat(dc, &pfd);
98 if (!SetPixelFormat(dc, pxfmt, &pfd))
100 Close();
101 return false;
104 m_glrc = wglCreateContext(dc);
105 if (!wglMakeCurrent(dc, m_glrc)) // render context should stay current throughout
107 Close();
108 return false;
111 char *rendstr = (char*) glGetString(GL_RENDERER);
112 if (!rendstr || strstr(rendstr, "GDI"))
114 Close();
115 return false;
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"))
123 Close();
124 return false;
127 // any one-time initialization goes here
128 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
130 ReleaseDC(m_hwnd, dc);
132 return true;
135 bool LICE_GL_ctx::IsValid()
137 if (m_gldll && m_glrc) return true;
138 if (!m_init_tried) return Init();
139 return false;
142 void LICE_GL_ctx::Close()
144 ClearTex();
145 if (m_nurbs)
147 gluDeleteNurbsRenderer(m_nurbs);
148 m_nurbs = 0;
150 if (m_glrc)
152 wglMakeCurrent(0, 0);
153 wglDeleteContext(m_glrc);
154 m_glrc = 0;
156 if (m_hwnd)
158 DestroyWindow(m_hwnd);
159 m_hwnd = 0;
161 if (m_gldll)
163 FreeLibrary(m_gldll);
164 m_gldll = 0;
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);
173 return m_nurbs;
176 void LICE_GL_ctx::ClearTex()
178 int i;
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));
185 m_nCachedGlyphs = 0;
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;
204 GlyphCache gc;
205 gc.tex = 0;
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);
226 return gc.tex;
229 ////////
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();
242 return 0;
245 void LICE_GL_CloseCtx()
247 s_glctx.Close();
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()
262 s_glctx.ClearTex();