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

Last change on this file since 2 was 2, checked in by Sam Hocevar, 18 years ago
  • imported original 0.7.0 tarball
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 xs, xe, ys, ye;
229        SDL_Rect srcrect, dstrect;
230        int ii, jj;
231        int srcx, srcy, xstep, ystep;
232        Uint8 *dpixel;
233        Uint16 dinset;
234        int dest_addr, line_width;
235
236        if( (unsigned)y > yres || (unsigned)x > xres )
237        {
238                return;
239        }
240        CHECK( x1 >= 0 && x2 >= x1 && y1 >= 0 && y2 >= y1 );
241
242        // Adjust if we are trying to draw off the screen
243        if( x < 0 )
244        {
245                x1 += -x;
246                x = 0;
247        }
248        srcrect.x = x1;
249        if( (unsigned)(x + ( x2 - x1 )) >= xres )
250        {
251                xe = xres - x + x1 - 1;
252        }
253        else
254        {
255                xe = x2;
256        }
257        if( y < 0 )
258        {
259                y1 += -y;
260                y = 0;
261        }
262        srcrect.y = y1;
263        if( (unsigned)(y + ( y2 - y1 )) >= yres )
264        {
265                ye = yres - y + y1 - 1;
266        }
267        else
268        {
269                ye = y2;
270        }
271        if( srcrect.x >= xe || srcrect.y >= ye )
272                return;
273
274        // Scale the image onto the surface
275        srcrect.w = xe - srcrect.x;
276        srcrect.h = ye - srcrect.y;
277        dstrect.x = ((x * win_xscale) >> 16);
278        dstrect.y = ((y * win_yscale) >> 16);
279        dstrect.w = ((srcrect.w * win_xscale) >> 16);
280        dstrect.h = ((srcrect.h * win_yscale) >> 16);
281
282        xstep = (srcrect.w << 16) / dstrect.w;
283        ystep = (srcrect.h << 16) / dstrect.h;
284
285        srcy = ((srcrect.y) << 16);
286        dinset = ((surface->w - dstrect.w)) * surface->format->BytesPerPixel;
287
288        // Lock the surface if necessary
289        if( SDL_MUSTLOCK( surface ) )
290        {
291                SDL_LockSurface( surface );
292        }
293        dpixel = (Uint8 *)surface->pixels;
294        dpixel += (dstrect.x + ((dstrect.y) * surface->w)) * surface->format->BytesPerPixel;
295
296        // Update surface part
297        if ((win_xscale==1<<16) && (win_yscale==1<<16)) // no scaling or hw scaling
298        {
299                srcy = srcrect.y;
300                dpixel = ((Uint8 *)surface->pixels) + y * surface->w + x ;
301                for( ii=0 ; ii < srcrect.h; ii++ )
302                {
303                        memcpy( dpixel, im->scan_line( srcy ) + srcrect.x , srcrect.w );
304                        dpixel += surface->w;
305                        srcy ++;
306                }
307        }
308        else    // sw scaling
309        {
310                xstep = (srcrect.w << 16) / dstrect.w;
311                ystep = (srcrect.h << 16) / dstrect.h;
312
313                srcy = ((srcrect.y) << 16);
314                dinset = ((surface->w - dstrect.w)) * surface->format->BytesPerPixel;
315
316                dpixel = (Uint8 *)surface->pixels + (dstrect.x + ((dstrect.y) * surface->w)) * surface->format->BytesPerPixel;
317
318                for( ii = 0; ii < dstrect.h; ii++ )
319                {
320                        srcx = (srcrect.x << 16);
321                        for( jj = 0; jj < dstrect.w; jj++ )
322                        {
323                                memcpy( dpixel, im->scan_line( (srcy >> 16) ) + ((srcx >> 16) * surface->format->BytesPerPixel), surface->format->BytesPerPixel );
324                                dpixel += surface->format->BytesPerPixel;
325                                srcx += xstep;
326                        }
327                        dpixel += dinset;
328                        srcy += ystep;
329                }
330//              dpixel += dinset;
331//              srcy += ystep;
332        }
333
334        // Unlock the surface if we locked it.
335        if( SDL_MUSTLOCK( surface ) )
336        {
337                SDL_UnlockSurface( surface );
338        }
339
340        // Now blit the surface
341        update_window_part( &dstrect);
342}
343
344//
345// put_image()
346// Draw the entire image
347//
348void put_image( image * im, int x, int y )
349{
350        put_part_image( im, x, y, 0, 0, im->width() - 1, im->height() - 1 );
351}
352
353//
354// update_dirty_window()
355// Update the dirty parts of the window
356//
357void update_dirty_window( image *im, int xoff, int yoff )
358{
359        int count;
360        dirty_rect *dr, *q;
361        CHECK( im->special ); // make sure the image has the ability to contain dirty areas
362        if( im->special->keep_dirt == 0 )
363        {
364                put_image( im, xoff, yoff );
365        }
366        else
367        {
368                count = im->special->dirties.number_nodes();
369                if( !count )
370                        return;  // if nothing to update, return
371                dr = (dirty_rect *)( im->special->dirties.first() );
372                while( count > 0 )
373                {
374                        put_part_image( im, xoff + dr->dx1, yoff + dr->dy1, dr->dx1, dr->dy1, dr->dx2 + 1, dr->dy2 + 1 );
375                        q = dr;
376                        dr = (dirty_rect *)( dr->next() );
377                        im->special->dirties.unlink( ( linked_node *)q );
378                        delete q;
379                        count--;
380                }
381        }
382}
383
384//
385// update_dirty()
386// Update the dirty parts of the image
387//
388void update_dirty( image *im, int xoff, int yoff )
389{
390        update_dirty_window( im, xoff, yoff );
391        update_window_done();
392}
393
394//
395// make_page()
396//
397void image::make_page( short width, short height, unsigned char *page_buffer )
398{
399        if( page_buffer )
400        {
401                data = page_buffer;
402        }
403        else
404        {
405                data = (unsigned char *)jmalloc( width * height, "image::data" );
406        }
407}
408
409//
410// delete_page()
411//
412void image::delete_page()
413{
414        if( !special || !special->static_mem )
415        {
416                jfree( data );
417        }
418}
419
420//
421// load()
422// Set the palette
423//
424void palette::load()
425{
426        if( lastl )
427        {
428                delete lastl;
429        }
430        lastl = copy();
431
432        // Force to only 256 colours.
433        // Shouldn't be needed, but best to be safe.
434        if( ncolors > 256 )
435        {
436                ncolors = 256;
437        }
438
439        SDL_Color colors[ncolors];
440        for( int ii = 0; ii < ncolors; ii++ )
441        {
442                colors[ii].r = red(ii);
443                colors[ii].g = green(ii);
444                colors[ii].b = blue(ii);
445        }
446        SDL_SetColors( surface, colors, 0, ncolors );
447        if( window->format->BitsPerPixel == 8 )
448        {
449                SDL_SetColors( window, colors, 0, ncolors );
450        }
451
452        // Now redraw the surface
453        update_window_part( NULL );
454        update_window_done();
455}
456
457//
458// load_nice()
459//
460void palette::load_nice()
461{
462        load();
463}
464
465// ---- support functions ----
466
467void update_window_done()
468{
469        // opengl blit complete surface to window
470        if (flags.gl)
471        {
472#ifdef HAVE_OPENGL
473                // convert color-indexed surface to RGB texture
474                SDL_BlitSurface( surface, NULL, texture, NULL );
475
476                // Texturemap complete texture to surface so we have free scaling
477                // and antialiasing
478                glTexSubImage2D( GL_TEXTURE_2D,0,
479                         0,0,texture->w,texture->h,
480                         GL_RGBA,GL_UNSIGNED_BYTE,texture->pixels);
481                glBegin(GL_TRIANGLE_STRIP);
482                glTexCoord2f(texcoord[0], texcoord[1]); glVertex3i(0, 0, 0);
483                glTexCoord2f(texcoord[2], texcoord[1]); glVertex3i(window->w, 0, 0);
484                glTexCoord2f(texcoord[0], texcoord[3]); glVertex3i(0, window->h, 0);
485                glTexCoord2f(texcoord[2], texcoord[3]); glVertex3i(window->w, window->h, 0);
486                glEnd();
487#endif
488        }
489
490        // swap buffers in case of double buffering
491        if (flags.doublebuf)
492        {
493                if (flags.gl)
494                {
495#ifdef HAVE_OPENGL
496                        SDL_GL_SwapBuffers();
497#endif
498                }
499                else
500                {
501                        SDL_Flip(window);
502                }
503        }
504
505        // do nothing in case of single buffering
506}
507
508void update_window_part( SDL_Rect *rect)
509{
510        // no partial blit's in case of opengl
511        // complete blit + scaling just before flip
512        if (flags.gl)
513        {
514                return;
515        }
516
517        SDL_BlitSurface( surface, rect, window, rect );
518
519        // no window update needed until end of run
520        if( flags.doublebuf)
521        {
522                return;
523        }
524
525        // update window part for single buffer
526        if( rect == NULL )
527        {
528                SDL_UpdateRect( window, 0, 0, 0, 0 );
529        }
530        else
531        {
532                SDL_UpdateRect( window, rect->x, rect->y, rect->w, rect->h );
533        }
534}
Note: See TracBrowser for help on using the repository browser.