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

Last change on this file since 162 was 162, checked in by Sam Hocevar, 13 years ago

Fix numerous compiler warnings.

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