4 * Common GL code that doesn't depend on a specific implementation
6 * Copyright (c) 2005 Nathan Keynes.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
22 #include "pvr2/pvr2.h"
23 #include "pvr2/glutil.h"
24 #include "pvr2/shaders.h"
25 #include "drivers/video_gl.h"
27 /* FIXME: Need to actually handle this case */
28 #ifndef GL_PACK_ROW_LENGTH
29 #define glPixelStorei(key,val)
32 uint32_t video_width, video_height;
39 static struct video_box_t {
41 struct video_vertex gap1[4];
42 struct video_vertex gap2[4];
43 struct video_vertex video_view[4];
44 struct video_vertex invert_view[4];
47 void gl_set_video_size( uint32_t width, uint32_t height, int flipped )
50 video_height = height;
52 int x1=0,y1=0,x2=video_width,y2=video_height;
53 int top = 0, bottom = 1;
60 int ah = video_width * 0.75;
62 if( ah > video_height ) {
63 int w = (video_height/0.75);
64 x1 = (video_width - w)/2;
66 video_box.gap1[0].x = 0; video_box.gap1[0].y = 0;
67 video_box.gap1[1].x = x1; video_box.gap1[1].y = 0;
68 video_box.gap1[2].x = x1; video_box.gap1[2].y = video_height;
69 video_box.gap1[3].x = 0; video_box.gap1[3].y = video_height;
70 video_box.gap2[0].x = x2; video_box.gap2[0].y = 0;
71 video_box.gap2[1].x = video_width; video_box.gap2[1].y = 0;
72 video_box.gap2[2].x = video_width; video_box.gap2[2].y = video_height;
73 video_box.gap2[3].x = x2; video_box.gap2[3].y = video_height;
74 } else if( ah < video_height ) {
75 y1 = (video_height - ah)/2;
78 video_box.gap1[0].x = 0; video_box.gap1[0].y = 0;
79 video_box.gap1[1].x = video_width; video_box.gap1[1].y = 0;
80 video_box.gap1[2].x = video_width; video_box.gap1[2].y = y1;
81 video_box.gap1[3].x = 0; video_box.gap1[3].y = y1;
82 video_box.gap2[0].x = 0; video_box.gap2[0].y = y2;
83 video_box.gap2[1].x = video_width; video_box.gap2[1].y = y2;
84 video_box.gap2[2].x = video_width; video_box.gap2[2].y = video_height;
85 video_box.gap2[3].x = 0; video_box.gap2[3].y = video_height;
88 video_box.video_view[0].x = x1; video_box.video_view[0].y = y1;
89 video_box.video_view[0].u = 0; video_box.video_view[0].v = top;
90 video_box.video_view[1].x = x2; video_box.video_view[1].y = y1;
91 video_box.video_view[1].u = 1; video_box.video_view[1].v = top;
92 video_box.video_view[2].x = x2; video_box.video_view[2].y = y2;
93 video_box.video_view[2].u = 1; video_box.video_view[2].v = bottom;
94 video_box.video_view[3].x = x1; video_box.video_view[3].y = y2;
95 video_box.video_view[3].u = 0; video_box.video_view[3].v = bottom;
97 memcpy( &video_box.invert_view, &video_box.video_view, sizeof(video_box.video_view) );
98 video_box.invert_view[0].v = bottom; video_box.invert_view[1].v = bottom;
99 video_box.invert_view[2].v = top; video_box.invert_view[3].v = top;
101 defineOrthoMatrix(video_box.viewMatrix, video_width, video_height, 0, 65535);
104 #ifdef HAVE_OPENGL_FIXEDFUNC
106 * Setup the gl context for writes to the display output.
108 void gl_framebuffer_setup()
110 glViewport( 0, 0, video_width, video_height );
111 glLoadMatrixf(video_box.viewMatrix);
112 glBlendFunc( GL_ONE, GL_ZERO );
113 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
114 glVertexPointer(2, GL_FLOAT, sizeof(struct video_vertex), &video_box.gap1[0].x);
115 glColorPointer(3, GL_FLOAT, sizeof(struct video_vertex), &video_box.gap1[0].r);
116 glTexCoordPointer(2, GL_FLOAT, sizeof(struct video_vertex), &video_box.gap1[0].u);
117 glEnableClientState( GL_VERTEX_ARRAY );
118 glEnableClientState( GL_COLOR_ARRAY );
119 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
122 void gl_framebuffer_cleanup()
124 glDisableClientState( GL_VERTEX_ARRAY );
125 glDisableClientState( GL_COLOR_ARRAY );
126 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
129 void gl_framebuffer_setup()
131 glViewport( 0, 0, video_width, video_height );
132 glBlendFunc( GL_ONE, GL_ZERO );
133 glsl_use_basic_shader();
134 glsl_set_basic_shader_view_matrix(video_box.viewMatrix);
135 glsl_set_basic_shader_in_vertex_pointer(&video_box.gap1[0].x, sizeof(struct video_vertex));
136 glsl_set_basic_shader_in_colour_pointer(&video_box.gap1[0].r, sizeof(struct video_vertex));
137 glsl_set_basic_shader_in_texcoord_pointer(&video_box.gap1[0].u, sizeof(struct video_vertex));
138 glsl_set_basic_shader_primary_texture(0);
141 void gl_framebuffer_cleanup()
147 void gl_display_render_buffer( render_buffer_t buffer )
149 gl_texture_window( buffer->width, buffer->height, buffer->buf_id, buffer->inverted );
153 * Convert window coordinates to dreamcast device coords (640x480) using the
154 * same viewable area as gl_texture_window.
155 * If the coordinates are outside the viewable area, the result is -1,-1.
157 void gl_window_to_system_coords( int *x, int *y )
159 int x1=0,y1=0,x2=video_width,y2=video_height;
161 int ah = video_width * 0.75;
163 if( ah > video_height ) {
164 int w = (video_height/0.75);
165 x1 = (video_width - w)/2;
167 } else if( ah < video_height ) {
168 y1 = (video_height - ah)/2;
171 if( *x < x1 || *x >= x2 || *y < y1 || *y >= y2 ) {
175 *x = (*x - x1) * DISPLAY_WIDTH / (x2-x1);
176 *y = (*y - y1) * DISPLAY_HEIGHT / (y2-y1);
181 * Use quads if we have them, otherwise tri-fans.
184 #define GL_QUADS GL_TRIANGLE_FAN
187 void gl_texture_window( int width, int height, int tex_id, gboolean inverted )
189 /* Set video box tex alpha to 1 */
190 video_box.video_view[0].a = video_box.video_view[1].a = video_box.video_view[2].a = video_box.video_view[3].a = 1;
191 video_box.invert_view[0].a = video_box.invert_view[1].a = video_box.invert_view[2].a = video_box.invert_view[3].a = 1;
193 /* Reset display parameters */
194 gl_framebuffer_setup();
195 glDrawArrays(GL_QUADS, 0, 4);
196 glDrawArrays(GL_QUADS, 4, 4);
197 glEnable(GL_TEXTURE_2D);
198 glBindTexture(GL_TEXTURE_2D,tex_id);
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
201 glDrawArrays(GL_QUADS, inverted ? 12 : 8, 4);
202 glDisable(GL_TEXTURE_2D);
203 gl_framebuffer_cleanup();
207 gboolean gl_load_frame_buffer( frame_buffer_t frame, int tex_id )
209 GLenum type = colour_formats[frame->colour_format].type;
210 GLenum format = colour_formats[frame->colour_format].format;
211 int bpp = colour_formats[frame->colour_format].bpp;
212 int rowstride = (frame->rowstride / bpp) - frame->width;
214 glPixelStorei( GL_UNPACK_ROW_LENGTH, rowstride );
215 glBindTexture( GL_TEXTURE_2D, tex_id );
216 glTexSubImage2D( GL_TEXTURE_2D, 0, 0,0,
217 frame->width, frame->height, format, type, frame->data );
218 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
222 void gl_display_blank( uint32_t colour )
224 /* Set the video_box background colour */
225 video_box.video_view[0].r = ((float)(((colour >> 16) & 0xFF) + 1)) / 256.0;
226 video_box.video_view[0].g = ((float)(((colour >> 8) & 0xFF) + 1)) / 256.0;
227 video_box.video_view[0].b = ((float)((colour & 0xFF) + 1)) / 256.0;
228 video_box.video_view[0].a = 0;
229 memcpy( &video_box.video_view[1].r, &video_box.video_view[0].r, sizeof(float)*3 );
230 memcpy( &video_box.video_view[2].r, &video_box.video_view[0].r, sizeof(float)*3 );
231 memcpy( &video_box.video_view[3].r, &video_box.video_view[0].r, sizeof(float)*3 );
234 gl_framebuffer_setup();
235 glDrawArrays(GL_QUADS, 0, 4);
236 glDrawArrays(GL_QUADS, 4, 4);
237 glDrawArrays(GL_QUADS, 8, 4);
238 gl_framebuffer_cleanup();
243 * Generic GL read_render_buffer. This function assumes that the caller
244 * has already set the appropriate glReadBuffer(); in other words, unless
245 * there's only one buffer this needs to be wrapped.
247 gboolean gl_read_render_buffer( unsigned char *target, render_buffer_t buffer,
248 int rowstride, int colour_format )
251 GLenum type = colour_formats[colour_format].type;
252 GLenum format = colour_formats[colour_format].format;
253 // int line_size = buffer->width * colour_formats[colour_format].bpp;
254 // int size = line_size * buffer->height;
255 int glrowstride = (rowstride / colour_formats[colour_format].bpp) - buffer->width;
256 glPixelStorei( GL_PACK_ROW_LENGTH, glrowstride );
257 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
258 glPixelStorei( GL_PACK_ROW_LENGTH, 0 );
262 gboolean gl_init_driver( display_driver_t driver, gboolean need_fbo )
264 /* Use framebuffer objects if available */
265 if( gl_fbo_is_supported() ) {
267 } else if( need_fbo ) {
268 ERROR( "Framebuffer objects not supported - unable to construct an off-screen buffer" );
272 /* Use SL shaders if available */
273 gboolean have_shaders = glsl_init(driver);
274 #ifndef HAVE_OPENGL_FIXEDFUNC
275 if( !have_shaders ) { /* Shaders are required if we don't have fixed-functionality */
281 /* Use vertex arrays, VBOs, etc, if we have them */
284 driver->capabilities.has_gl = TRUE;
288 static gboolean video_gl_init();
291 * Minimal GL driver (assuming that the GL context is already set up externally)
292 * This requires FBO support (since otherwise we have no way to get a render buffer)
294 struct display_driver display_gl_driver = {
295 "gl", N_("OpenGL driver"), video_gl_init, NULL,
297 NULL, NULL, NULL, NULL,
298 gl_load_frame_buffer, gl_display_render_buffer, gl_display_blank,
299 NULL, gl_read_render_buffer, NULL, NULL
302 static gboolean video_gl_init()
304 return gl_init_driver(&display_gl_driver, TRUE);
.