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

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