source: abuse/trunk/src/sdlport/video.cpp @ 18

Last change on this file since 18 was 4, checked in by Sam Hocevar, 17 years ago
  • debian patches
File size: 11.1 KB
Line 
1/************************
2 * video.c
3 * SDL port for Abuse
4 * by Anthony Kruize
5 ************************/
6
7#include <SDL.h>
8#ifdef HAVE_OPENGL
9#ifdef __APPLE__
10#include <OpenGL/gl.h>
11#include <OpenGL/glu.h>
12#else
13#include <GL/gl.h>
14#include <GL/glu.h>
15#endif  /* __APPLE__ */
16#endif  /* HAVE_OPENGL */
17#include "filter.hpp"
18#include "globals.hpp"
19#include "system.h"
20#include "video.hpp"
21#include "macs.hpp"
22#include "image.hpp"
23#include "jmalloc.hpp"
24#include "setup.h"
25
26SDL_Surface *window = NULL, *surface = NULL;
27image *screen = NULL;
28unsigned char current_background;
29int win_xscale, win_yscale, mouse_xscale, mouse_yscale;
30extern unsigned int xres, yres;
31extern palette *lastl;
32extern flags_struct flags;
33#ifdef HAVE_OPENGL
34GLfloat texcoord[4];
35GLuint texid;
36SDL_Surface *texture = NULL;
37#endif
38
39// Forward declarations
40void update_window_part(SDL_Rect *rect);
41void update_window_done();
42
43//
44// power_of_two()
45// Get the nearest power of two
46//
47static int power_of_two(int input)
48{
49        int value;
50        for( value = 1 ; value < input ; value <<= 1);
51        return value;
52}
53
54//
55// set_mode()
56// Set the video mode
57//
58void set_mode( int mode, int argc, char **argv )
59{
60        const SDL_VideoInfo *vidInfo;
61        int vidFlags = SDL_HWPALETTE;
62
63        // Check for video capabilities
64        vidInfo = SDL_GetVideoInfo();
65        if( vidInfo->hw_available )
66        {
67                vidFlags |= SDL_HWSURFACE;
68        }
69        else
70        {
71                vidFlags |= SDL_SWSURFACE;
72        }
73        if( flags.fullscreen )
74        {
75                vidFlags |= SDL_FULLSCREEN;
76        }
77        if( flags.doublebuf )
78        {
79                vidFlags |= SDL_DOUBLEBUF;
80        }
81
82        // Calculate the window scale
83        win_xscale = mouse_xscale = (flags.xres << 16) / xres;
84        win_yscale = mouse_yscale = (flags.yres << 16) / yres;
85
86        // Try using opengl hw accell
87        if( flags.gl ) {
88#ifdef HAVE_OPENGL
89                printf( "Video : OpenGL enabled\n" );
90                // allow doublebuffering in with gl too
91                SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, flags.doublebuf );
92                // set video gl capability
93                vidFlags |= SDL_OPENGL;
94                // force no scaling, let the hw do it
95                win_xscale = win_yscale = 1 << 16;
96#else
97                // ignore the option if not available
98                printf( "Video : OpenGL disabled (Support missing in executable)\n");
99                flags.gl = 0;
100#endif
101        }
102
103        // Set the icon for this window.  Looks nice on taskbars etc.
104        SDL_WM_SetIcon( SDL_LoadBMP("abuse.bmp"), NULL );
105
106        // Create the window with a preference for 8-bit (palette animations!), but accept any depth */
107        window = SDL_SetVideoMode(flags.xres, flags.yres, 8, vidFlags | SDL_ANYFORMAT );
108        if( window == NULL )
109        {
110                printf( "Video : Unable to set video mode : %s\n", SDL_GetError() );
111                exit( 1 );
112        }
113
114        // Create the screen image
115        screen = new image( xres, yres, NULL, 2 );
116        if( screen == NULL )
117        {
118                // Our screen image is no good, we have to bail.
119                printf( "Video : Unable to create screen image.\n" );
120                exit( 1 );
121        }
122        screen->clear();
123
124        if (flags.gl)
125        {
126#ifdef HAVE_OPENGL
127                int w,h;
128
129                // texture width/height should be power of 2
130                w = power_of_two(xres);
131                h = power_of_two(yres);
132
133                // create texture surface
134                texture = SDL_CreateRGBSurface( SDL_SWSURFACE, w ,h ,32,
135#if SDL_BYTEORDER == SDL_LIL_ENDIAN
136                                0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 );
137#else
138                                0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF );
139#endif
140
141                // setup 2D gl environment
142                glPushAttrib(GL_ENABLE_BIT);
143                glDisable(GL_DEPTH_TEST);
144                glDisable(GL_CULL_FACE);
145                glEnable(GL_TEXTURE_2D);
146
147                glViewport(0, 0, window->w, window->h);
148
149                glMatrixMode(GL_PROJECTION);
150                glPushMatrix();
151                glLoadIdentity();
152
153                glOrtho(0.0, (GLdouble)window->w, (GLdouble)window->h, 0.0, 0.0,1.0);
154
155                glMatrixMode(GL_MODELVIEW);
156                glPushMatrix();
157                glLoadIdentity();
158
159                // texture coordinates
160                texcoord[0] = 0.0f;
161                texcoord[1] = 0.0f;
162                texcoord[2] = (GLfloat)xres / texture->w;
163                texcoord[3] = (GLfloat)yres / texture->h;
164
165                // create an RGBA texture for the texture surface
166                glGenTextures(1, &texid);
167                glBindTexture(GL_TEXTURE_2D, texid);
168                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, flags.antialias);
169                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, flags.antialias);
170                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->w, texture->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture->pixels );
171#endif
172        }
173
174        // Create our 8-bit surface
175        surface = SDL_CreateRGBSurface( SDL_SWSURFACE, window->w, window->h, 8, 0xff, 0xff, 0xff, 0xff );
176        if( surface == NULL )
177        {
178                // Our surface is no good, we have to bail.
179                printf( "Video : Unable to create 8-bit surface.\n" );
180                exit( 1 );
181        }
182
183        printf( "Video : %dx%d %dbpp\n", window->w, window->h, window->format->BitsPerPixel );
184
185        // Set the window caption
186        SDL_WM_SetCaption( "Abuse-SDL", "Abuse-SDL" );
187
188        // Grab and hide the mouse cursor
189        SDL_ShowCursor( 0 );
190        if( flags.grabmouse )
191        {
192                SDL_WM_GrabInput( SDL_GRAB_ON );
193        }
194
195        update_dirty( screen );
196}
197
198//
199// close_graphics()
200// Shutdown the video mode
201//
202void close_graphics()
203{
204        if( lastl )
205        {
206                delete lastl;
207        }
208        lastl = NULL;
209        // Free our 8-bit surface
210        if( surface )
211        {
212                SDL_FreeSurface( surface );
213        }
214#ifdef HAVE_OPENGL
215        if ( texture )
216        {
217                SDL_FreeSurface( texture );
218        }
219#endif
220        delete screen;
221}
222
223// put_part_image()
224// Draw only dirty parts of the image
225//
226void put_part_image( image *im, int x, int y, int x1, int y1, int x2, int y2 )
227{
228        int xe, ye;
229        SDL_Rect srcrect, dstrect;
230        int ii, jj;
231        int srcx, srcy, xstep, ystep;
232        Uint8 *dpixel;
233        Uint16 dinset;
234
235        if( (unsigned)y > yres || (unsigned)x > xres )
236        {
237                return;
238        }
239        CHECK( x1 >= 0 && x2 >= x1 && y1 >= 0 && y2 >= y1 );
240
241        // Adjust if we are trying to draw off the screen
242        if( x < 0 )
243        {
244                x1 += -x;
245                x = 0;
246        }
247        srcrect.x = x1;
248        if( (unsigned)(x + ( x2 - x1 )) >= xres )
249        {
250                xe = xres - x + x1 - 1;
251        }
252        else
253        {
254                xe = x2;
255        }
256        if( y < 0 )
257        {
258                y1 += -y;
259                y = 0;
260        }
261        srcrect.y = y1;
262        if( (unsigned)(y + ( y2 - y1 )) >= yres )
263        {
264                ye = yres - y + y1 - 1;
265        }
266        else
267        {
268                ye = y2;
269        }
270        if( srcrect.x >= xe || srcrect.y >= ye )
271                return;
272
273        // Scale the image onto the surface
274        srcrect.w = xe - srcrect.x;
275        srcrect.h = ye - srcrect.y;
276        dstrect.x = ((x * win_xscale) >> 16);
277        dstrect.y = ((y * win_yscale) >> 16);
278        dstrect.w = ((srcrect.w * win_xscale) >> 16);
279        dstrect.h = ((srcrect.h * win_yscale) >> 16);
280
281        xstep = (srcrect.w << 16) / dstrect.w;
282        ystep = (srcrect.h << 16) / dstrect.h;
283
284        srcy = ((srcrect.y) << 16);
285        dinset = ((surface->w - dstrect.w)) * surface->format->BytesPerPixel;
286
287        // Lock the surface if necessary
288        if( SDL_MUSTLOCK( surface ) )
289        {
290                SDL_LockSurface( surface );
291        }
292        dpixel = (Uint8 *)surface->pixels;
293        dpixel += (dstrect.x + ((dstrect.y) * surface->w)) * surface->format->BytesPerPixel;
294
295        // Update surface part
296        if ((win_xscale==1<<16) && (win_yscale==1<<16)) // no scaling or hw scaling
297        {
298                srcy = srcrect.y;
299                dpixel = ((Uint8 *)surface->pixels) + y * surface->w + x ;
300                for( ii=0 ; ii < srcrect.h; ii++ )
301                {
302                        memcpy( dpixel, im->scan_line( srcy ) + srcrect.x , srcrect.w );
303                        dpixel += surface->w;
304                        srcy ++;
305                }
306        }
307        else    // sw scaling
308        {
309                xstep = (srcrect.w << 16) / dstrect.w;
310                ystep = (srcrect.h << 16) / dstrect.h;
311
312                srcy = ((srcrect.y) << 16);
313                dinset = ((surface->w - dstrect.w)) * surface->format->BytesPerPixel;
314
315                dpixel = (Uint8 *)surface->pixels + (dstrect.x + ((dstrect.y) * surface->w)) * surface->format->BytesPerPixel;
316
317                for( ii = 0; ii < dstrect.h; ii++ )
318                {
319                        srcx = (srcrect.x << 16);
320                        for( jj = 0; jj < dstrect.w; jj++ )
321                        {
322                                memcpy( dpixel, im->scan_line( (srcy >> 16) ) + ((srcx >> 16) * surface->format->BytesPerPixel), surface->format->BytesPerPixel );
323                                dpixel += surface->format->BytesPerPixel;
324                                srcx += xstep;
325                        }
326                        dpixel += dinset;
327                        srcy += ystep;
328                }
329//              dpixel += dinset;
330//              srcy += ystep;
331        }
332
333        // Unlock the surface if we locked it.
334        if( SDL_MUSTLOCK( surface ) )
335        {
336                SDL_UnlockSurface( surface );
337        }
338
339        // Now blit the surface
340        update_window_part( &dstrect);
341}
342
343//
344// put_image()
345// Draw the entire image
346//
347void put_image( image * im, int x, int y )
348{
349        put_part_image( im, x, y, 0, 0, im->width() - 1, im->height() - 1 );
350}
351
352//
353// update_dirty_window()
354// Update the dirty parts of the window
355//
356void update_dirty_window( image *im, int xoff, int yoff )
357{
358        int count;
359        dirty_rect *dr, *q;
360        CHECK( im->special ); // make sure the image has the ability to contain dirty areas
361        if( im->special->keep_dirt == 0 )
362        {
363                put_image( im, xoff, yoff );
364        }
365        else
366        {
367                count = im->special->dirties.number_nodes();
368                if( !count )
369                        return;  // if nothing to update, return
370                dr = (dirty_rect *)( im->special->dirties.first() );
371                while( count > 0 )
372                {
373                        put_part_image( im, xoff + dr->dx1, yoff + dr->dy1, dr->dx1, dr->dy1, dr->dx2 + 1, dr->dy2 + 1 );
374                        q = dr;
375                        dr = (dirty_rect *)( dr->next() );
376                        im->special->dirties.unlink( ( linked_node *)q );
377                        delete q;
378                        count--;
379                }
380        }
381}
382
383//
384// update_dirty()
385// Update the dirty parts of the image
386//
387void update_dirty( image *im, int xoff, int yoff )
388{
389        update_dirty_window( im, xoff, yoff );
390        update_window_done();
391}
392
393//
394// make_page()
395//
396void image::make_page( short width, short height, unsigned char *page_buffer )
397{
398        if( page_buffer )
399        {
400                data = page_buffer;
401        }
402        else
403        {
404                data = (unsigned char *)jmalloc( width * height, "image::data" );
405        }
406}
407
408//
409// delete_page()
410//
411void image::delete_page()
412{
413        if( !special || !special->static_mem )
414        {
415                jfree( data );
416        }
417}
418
419//
420// load()
421// Set the palette
422//
423void palette::load()
424{
425        if( lastl )
426        {
427                delete lastl;
428        }
429        lastl = copy();
430
431        // Force to only 256 colours.
432        // Shouldn't be needed, but best to be safe.
433        if( ncolors > 256 )
434        {
435                ncolors = 256;
436        }
437
438        SDL_Color colors[ncolors];
439        for( int ii = 0; ii < ncolors; ii++ )
440        {
441                colors[ii].r = red(ii);
442                colors[ii].g = green(ii);
443                colors[ii].b = blue(ii);
444        }
445        SDL_SetColors( surface, colors, 0, ncolors );
446        if( window->format->BitsPerPixel == 8 )
447        {
448                SDL_SetColors( window, colors, 0, ncolors );
449        }
450
451        // Now redraw the surface
452        update_window_part( NULL );
453        update_window_done();
454}
455
456//
457// load_nice()
458//
459void palette::load_nice()
460{
461        load();
462}
463
464// ---- support functions ----
465
466void update_window_done()
467{
468        // opengl blit complete surface to window
469        if (flags.gl)
470        {
471#ifdef HAVE_OPENGL
472                // convert color-indexed surface to RGB texture
473                SDL_BlitSurface( surface, NULL, texture, NULL );
474
475                // Texturemap complete texture to surface so we have free scaling
476                // and antialiasing
477                glTexSubImage2D( GL_TEXTURE_2D,0,
478                         0,0,texture->w,texture->h,
479                         GL_RGBA,GL_UNSIGNED_BYTE,texture->pixels);
480                glBegin(GL_TRIANGLE_STRIP);
481                glTexCoord2f(texcoord[0], texcoord[1]); glVertex3i(0, 0, 0);
482                glTexCoord2f(texcoord[2], texcoord[1]); glVertex3i(window->w, 0, 0);
483                glTexCoord2f(texcoord[0], texcoord[3]); glVertex3i(0, window->h, 0);
484                glTexCoord2f(texcoord[2], texcoord[3]); glVertex3i(window->w, window->h, 0);
485                glEnd();
486#endif
487        }
488
489        // swap buffers in case of double buffering
490        if (flags.doublebuf)
491        {
492                if (flags.gl)
493                {
494#ifdef HAVE_OPENGL
495                        SDL_GL_SwapBuffers();
496#endif
497                }
498                else
499                {
500                        SDL_Flip(window);
501                }
502        }
503
504        // do nothing in case of single buffering
505}
506
507void update_window_part( SDL_Rect *rect)
508{
509        // no partial blit's in case of opengl
510        // complete blit + scaling just before flip
511        if (flags.gl)
512        {
513                return;
514        }
515
516        SDL_BlitSurface( surface, rect, window, rect );
517
518        // no window update needed until end of run
519        if( flags.doublebuf)
520        {
521                return;
522        }
523
524        // update window part for single buffer
525        if( rect == NULL )
526        {
527                SDL_UpdateRect( window, 0, 0, 0, 0 );
528        }
529        else
530        {
531                SDL_UpdateRect( window, rect->x, rect->y, rect->w, rect->h );
532        }
533}
Note: See TracBrowser for help on using the repository browser.