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

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