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

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