1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 /*
21 ** GLW_IMP.C
22 **
23 ** This file contains ALL Linux specific stuff having to do with the
24 ** OpenGL refresh.  When a port is being made the following functions
25 ** must be implemented by the port:
26 **
27 ** GLimp_EndFrame
28 ** GLimp_Init
29 ** GLimp_Shutdown
30 ** GLimp_SwitchFullscreen
31 **
32 */
33 
34 #include <termios.h>
35 #include <sys/ioctl.h>
36 #include <sys/stat.h>
37 #include <sys/vt.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <signal.h>
41 #include <dlfcn.h>
42 
43 #include "../ref_gl/gl_local.h"
44 #include "../client/keys.h"
45 #include "../linux/rw_linux.h"
46 
47 #include "../linux/glw_linux.h"
48 
49 #include <GL/fxmesa.h>
50 
51 /*****************************************************************************/
52 
53 glwstate_t glw_state;
54 
55 static qboolean GLimp_SwitchFullscreen( int width, int height );
56 qboolean GLimp_InitGL (void);
57 qboolean have_stencil = false;
58 
59 extern cvar_t *vid_fullscreen;
60 extern cvar_t *vid_ref;
61 
62 static fxMesaContext fc = NULL;
63 
64 //FX Mesa Functions
65 fxMesaContext (*qfxMesaCreateContext)(GLuint win, GrScreenResolution_t, GrScreenRefresh_t, const GLint attribList[]);
66 fxMesaContext (*qfxMesaCreateBestContext)(GLuint win, GLint width, GLint height, const GLint attribList[]);
67 void (*qfxMesaDestroyContext)(fxMesaContext ctx);
68 void (*qfxMesaMakeCurrent)(fxMesaContext ctx);
69 fxMesaContext (*qfxMesaGetCurrentContext)(void);
70 void (*qfxMesaSwapBuffers)(void);
71 
72 
73 #define NUM_RESOLUTIONS 16
74 
75 static resolutions[NUM_RESOLUTIONS][3]={
76 	{ 320,200,  GR_RESOLUTION_320x200 },
77 	{ 320,240,  GR_RESOLUTION_320x240 },
78 	{ 400,256,  GR_RESOLUTION_400x256 },
79 	{ 400,300,  GR_RESOLUTION_400x300 },
80 	{ 512,384,  GR_RESOLUTION_512x384 },
81 	{ 640,200,  GR_RESOLUTION_640x200 },
82 	{ 640,350,  GR_RESOLUTION_640x350 },
83 	{ 640,400,  GR_RESOLUTION_640x400 },
84 	{ 640,480,  GR_RESOLUTION_640x480 },
85 	{ 800,600,  GR_RESOLUTION_800x600 },
86 	{ 960,720,  GR_RESOLUTION_960x720 },
87 	{ 856,480,  GR_RESOLUTION_856x480 },
88 	{ 512,256,  GR_RESOLUTION_512x256 },
89 	{ 1024,768, GR_RESOLUTION_1024x768 },
90 	{ 1280,1024,GR_RESOLUTION_1280x1024 },
91 	{ 1600,1200,GR_RESOLUTION_1600x1200 }
92 };
93 
findres(int * width,int * height)94 static int findres(int *width, int *height)
95 {
96 	int i;
97 
98 	for(i=0;i<NUM_RESOLUTIONS;i++)
99 		if((*width<=resolutions[i][0]) && (*height<=resolutions[i][1])) {
100 			*width = resolutions[i][0];
101 			*height = resolutions[i][1];
102 			return resolutions[i][2];
103 		}
104 
105 	*width = 640;
106 	*height = 480;
107 	return GR_RESOLUTION_640x480;
108 }
109 
signal_handler(int sig)110 static void signal_handler(int sig)
111 {
112 	printf("Received signal %d, exiting...\n", sig);
113 	GLimp_Shutdown();
114 	_exit(0);
115 }
116 
InitSig(void)117 static void InitSig(void)
118 {
119 	signal(SIGHUP, signal_handler);
120 	signal(SIGQUIT, signal_handler);
121 	signal(SIGILL, signal_handler);
122 	signal(SIGTRAP, signal_handler);
123 	signal(SIGIOT, signal_handler);
124 	signal(SIGBUS, signal_handler);
125 	signal(SIGFPE, signal_handler);
126 	signal(SIGSEGV, signal_handler);
127 	signal(SIGTERM, signal_handler);
128 }
129 
130 /*
131 ** GLimp_SetMode
132 */
GLimp_SetMode(int * pwidth,int * pheight,int mode,qboolean fullscreen)133 int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
134 {
135 	int width, height;
136 	GLint attribs[32];
137 
138 	ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
139 
140 	ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
141 
142 	if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
143 	{
144 		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
145 		return rserr_invalid_mode;
146 	}
147 
148 	ri.Con_Printf( PRINT_ALL, " %d %d\n", width, height );
149 
150 	// destroy the existing window
151 	GLimp_Shutdown ();
152 
153 	// set fx attribs
154 	attribs[0] = FXMESA_DOUBLEBUFFER;
155 	attribs[1] = FXMESA_ALPHA_SIZE;
156 	attribs[2] = 1;
157 	attribs[3] = FXMESA_DEPTH_SIZE;
158 	attribs[4] = 1;
159 	attribs[5] = FXMESA_NONE;
160 
161 	fc = qfxMesaCreateContext(0, findres(&width, &height), GR_REFRESH_75Hz,
162 		attribs);
163 	if (!fc)
164 		return rserr_invalid_mode;
165 
166 	*pwidth = width;
167 	*pheight = height;
168 
169 	// let the sound and input subsystems know about the new window
170 	ri.Vid_NewWindow (width, height);
171 
172 	qfxMesaMakeCurrent(fc);
173 
174 	return rserr_ok;
175 }
176 
177 /*
178 ** GLimp_Shutdown
179 **
180 ** This routine does all OS specific shutdown procedures for the OpenGL
181 ** subsystem.  Under OpenGL this means NULLing out the current DC and
182 ** HGLRC, deleting the rendering context, and releasing the DC acquired
183 ** for the window.  The state structure is also nulled out.
184 **
185 */
GLimp_Shutdown(void)186 void GLimp_Shutdown( void )
187 {
188 	if (fc) {
189 		qfxMesaDestroyContext(fc);
190 		fc = NULL;
191 	}
192 /*
193 	qfxMesaCreateContext         = NULL;
194 	qfxMesaCreateBestContext     = NULL;
195 	qfxMesaDestroyContext        = NULL;
196 	qfxMesaMakeCurrent           = NULL;
197 	qfxMesaGetCurrentContext     = NULL;
198 	qfxMesaSwapBuffers           = NULL;
199 */
200 }
201 
202 /*
203 ** GLimp_Init
204 **
205 ** This routine is responsible for initializing the OS specific portions
206 ** of OpenGL.
207 */
GLimp_Init(void * hinstance,void * wndproc)208 int GLimp_Init( void *hinstance, void *wndproc )
209 {
210 	InitSig();
211 
212 	if ( glw_state.OpenGLLib ) {
213 		#define GPA( a ) dlsym( glw_state.OpenGLLib, a )
214 
215 		qfxMesaCreateContext         =  GPA("fxMesaCreateContext");
216 		qfxMesaCreateBestContext     =  GPA("fxMesaCreateBestContext");
217 		qfxMesaDestroyContext        =  GPA("fxMesaDestroyContext");
218 		qfxMesaMakeCurrent           =  GPA("fxMesaMakeCurrent");
219 		qfxMesaGetCurrentContext     =  GPA("fxMesaGetCurrentContext");
220 		qfxMesaSwapBuffers           =  GPA("fxMesaSwapBuffers");
221 
222 		return true;
223 	}
224 
225 	return false;
226 }
227 
228 /*
229 ** GLimp_BeginFrame
230 */
GLimp_BeginFrame(float camera_seperation)231 void GLimp_BeginFrame( float camera_seperation )
232 {
233 }
234 
235 /*
236 ** GLimp_EndFrame
237 **
238 ** Responsible for doing a swapbuffers and possibly for other stuff
239 ** as yet to be determined.  Probably better not to make this a GLimp
240 ** function and instead do a call to GLimp_SwapBuffers.
241 */
GLimp_EndFrame(void)242 void GLimp_EndFrame (void)
243 {
244 	qglFlush();
245 	qfxMesaSwapBuffers();
246 }
247 
248 /*
249 ** GLimp_AppActivate
250 */
GLimp_AppActivate(qboolean active)251 void GLimp_AppActivate( qboolean active )
252 {
253 }
254 
Fake_glColorTableEXT(GLenum target,GLenum internalformat,GLsizei width,GLenum format,GLenum type,const GLvoid * table)255 void Fake_glColorTableEXT( GLenum target, GLenum internalformat,
256                              GLsizei width, GLenum format, GLenum type,
257                              const GLvoid *table )
258 {
259 	byte temptable[256][4];
260 	byte *intbl;
261 	int i;
262 
263 	for (intbl = (byte *)table, i = 0; i < 256; i++) {
264 		temptable[i][2] = *intbl++;
265 		temptable[i][1] = *intbl++;
266 		temptable[i][0] = *intbl++;
267 		temptable[i][3] = 255;
268 	}
269 	qglEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
270 	qgl3DfxSetPaletteEXT((GLuint *)temptable);
271 }
272 
273