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

Last change on this file since 523 was 523, checked in by Sam Hocevar, 12 years ago

imlib: remove dead code.

File size: 12.6 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 2001 Anthony Kruize <trandor@labyrinth.net.au>
4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This program is free software; you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation; either version 2 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program; if not, write to the Free Software Foundation,
18 *  Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 */
20
21#include "config.h"
22
23#include <SDL.h>
24
25#ifdef HAVE_OPENGL
26#   ifdef __APPLE__
27#       include <OpenGL/gl.h>
28#       include <OpenGL/glu.h>
29#   else
30#       include <GL/gl.h>
31#       include <GL/glu.h>
32#   endif    /* __APPLE__ */
33#endif    /* HAVE_OPENGL */
34
35#include "common.h"
36
37#include "filter.h"
38#include "system.h"
39#include "video.h"
40#include "macs.h"
41#include "image.h"
42#include "setup.h"
43
44SDL_Surface *window = NULL, *surface = NULL;
45image *screen = NULL;
46int win_xscale, win_yscale, mouse_xscale, mouse_yscale;
47int xres, yres;
48
49extern palette *lastl;
50extern flags_struct flags;
51#ifdef HAVE_OPENGL
52GLfloat texcoord[4];
53GLuint texid;
54SDL_Surface *texture = NULL;
55#endif
56
57// Forward declarations
58void update_window_part(SDL_Rect *rect);
59void update_window_done();
60
61//
62// power_of_two()
63// Get the nearest power of two
64//
65static int power_of_two(int input)
66{
67    int value;
68    for(value = 1 ; value < input ; value <<= 1);
69    return value;
70}
71
72//
73// set_mode()
74// Set the video mode
75//
76void set_mode(int mode, int argc, char **argv)
77{
78    const SDL_VideoInfo *vidInfo;
79    int vidFlags = SDL_HWPALETTE;
80
81    // Check for video capabilities
82    vidInfo = SDL_GetVideoInfo();
83    if(vidInfo->hw_available)
84        vidFlags |= SDL_HWSURFACE;
85    else
86        vidFlags |= SDL_SWSURFACE;
87
88    if(flags.fullscreen)
89        vidFlags |= SDL_FULLSCREEN;
90
91    if(flags.doublebuf)
92        vidFlags |= SDL_DOUBLEBUF;
93
94    // Calculate the window scale
95    win_xscale = mouse_xscale = (flags.xres << 16) / xres;
96    win_yscale = mouse_yscale = (flags.yres << 16) / yres;
97
98    // Try using opengl hw accell
99    if(flags.gl) {
100#ifdef HAVE_OPENGL
101        printf("Video : OpenGL enabled\n");
102        // allow doublebuffering in with gl too
103        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, flags.doublebuf);
104        // set video gl capability
105        vidFlags |= SDL_OPENGL;
106        // force no scaling, let the hw do it
107        win_xscale = win_yscale = 1 << 16;
108#else
109        // ignore the option if not available
110        printf("Video : OpenGL disabled (Support missing in executable)\n");
111        flags.gl = 0;
112#endif
113    }
114
115    // Set the icon for this window.  Looks nice on taskbars etc.
116    SDL_WM_SetIcon(SDL_LoadBMP("abuse.bmp"), NULL);
117
118    // Create the window with a preference for 8-bit (palette animations!), but accept any depth */
119    window = SDL_SetVideoMode(flags.xres, flags.yres, 8, vidFlags | SDL_ANYFORMAT);
120    if(window == NULL)
121    {
122        printf("Video : Unable to set video mode : %s\n", SDL_GetError());
123        exit(1);
124    }
125
126    // Create the screen image
127    screen = new image(vec2i(xres, yres), NULL, 2);
128    if(screen == NULL)
129    {
130        // Our screen image is no good, we have to bail.
131        printf("Video : Unable to create screen image.\n");
132        exit(1);
133    }
134    screen->clear();
135
136    if (flags.gl)
137    {
138#ifdef HAVE_OPENGL
139        int w, h;
140
141        // texture width/height should be power of 2
142        // FIXME: we can use GL_ARB_texture_non_power_of_two or
143        // GL_ARB_texture_rectangle to avoid the extra memory allocation
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", "Abuse");
201
202    // Grab and hide the mouse cursor
203    SDL_ShowCursor(0);
204    if(flags.grabmouse)
205        SDL_WM_GrabInput(SDL_GRAB_ON);
206
207    update_dirty(screen);
208}
209
210//
211// close_graphics()
212// Shutdown the video mode
213//
214void close_graphics()
215{
216    if(lastl)
217        delete lastl;
218    lastl = NULL;
219    // Free our 8-bit surface
220    if(surface)
221        SDL_FreeSurface(surface);
222
223#ifdef HAVE_OPENGL
224    if (texture)
225        SDL_FreeSurface(texture);
226#endif
227    delete screen;
228}
229
230// put_part_image()
231// Draw only dirty parts of the image
232//
233void put_part_image(image *im, int x, int y, int x1, int y1, int x2, int y2)
234{
235    int xe, ye;
236    SDL_Rect srcrect, dstrect;
237    int ii, jj;
238    int srcx, srcy, xstep, ystep;
239    Uint8 *dpixel;
240    Uint16 dinset;
241
242    if(y > yres || x > xres)
243        return;
244
245    CHECK(x1 >= 0 && x2 >= x1 && y1 >= 0 && y2 >= y1);
246
247    // Adjust if we are trying to draw off the screen
248    if(x < 0)
249    {
250        x1 += -x;
251        x = 0;
252    }
253    srcrect.x = x1;
254    if(x + (x2 - x1) >= xres)
255        xe = xres - x + x1 - 1;
256    else
257        xe = x2;
258
259    if(y < 0)
260    {
261        y1 += -y;
262        y = 0;
263    }
264    srcrect.y = y1;
265    if(y + (y2 - y1) >= yres)
266        ye = yres - y + y1 - 1;
267    else
268        ye = y2;
269
270    if(srcrect.x >= xe || srcrect.y >= ye)
271        return;
272
273    // Scale the image onto the surface
274    srcrect.w = xe - srcrect.x;
275    srcrect.h = ye - srcrect.y;
276    dstrect.x = ((x * win_xscale) >> 16);
277    dstrect.y = ((y * win_yscale) >> 16);
278    dstrect.w = ((srcrect.w * win_xscale) >> 16);
279    dstrect.h = ((srcrect.h * win_yscale) >> 16);
280
281    xstep = (srcrect.w << 16) / dstrect.w;
282    ystep = (srcrect.h << 16) / dstrect.h;
283
284    srcy = ((srcrect.y) << 16);
285    dinset = ((surface->w - dstrect.w)) * surface->format->BytesPerPixel;
286
287    // Lock the surface if necessary
288    if(SDL_MUSTLOCK(surface))
289        SDL_LockSurface(surface);
290
291    dpixel = (Uint8 *)surface->pixels;
292    dpixel += (dstrect.x + ((dstrect.y) * surface->w)) * surface->format->BytesPerPixel;
293
294    // Update surface part
295    if ((win_xscale==1<<16) && (win_yscale==1<<16)) // no scaling or hw scaling
296    {
297        srcy = srcrect.y;
298        dpixel = ((Uint8 *)surface->pixels) + y * surface->w + x ;
299        for(ii=0 ; ii < srcrect.h; ii++)
300        {
301            memcpy(dpixel, im->scan_line(srcy) + srcrect.x , srcrect.w);
302            dpixel += surface->w;
303            srcy ++;
304        }
305    }
306    else    // sw scaling
307    {
308        xstep = (srcrect.w << 16) / dstrect.w;
309        ystep = (srcrect.h << 16) / dstrect.h;
310
311        srcy = ((srcrect.y) << 16);
312        dinset = ((surface->w - dstrect.w)) * surface->format->BytesPerPixel;
313
314        dpixel = (Uint8 *)surface->pixels + (dstrect.x + ((dstrect.y) * surface->w)) * surface->format->BytesPerPixel;
315
316        for(ii = 0; ii < dstrect.h; ii++)
317        {
318            srcx = (srcrect.x << 16);
319            for(jj = 0; jj < dstrect.w; jj++)
320            {
321                memcpy(dpixel, im->scan_line((srcy >> 16)) + ((srcx >> 16) * surface->format->BytesPerPixel), surface->format->BytesPerPixel);
322                dpixel += surface->format->BytesPerPixel;
323                srcx += xstep;
324            }
325            dpixel += dinset;
326            srcy += ystep;
327        }
328//        dpixel += dinset;
329//        srcy += ystep;
330    }
331
332    // Unlock the surface if we locked it.
333    if(SDL_MUSTLOCK(surface))
334        SDL_UnlockSurface(surface);
335
336    // Now blit the surface
337    update_window_part(&dstrect);
338}
339
340//
341// put_image()
342// Draw the entire image
343//
344void put_image(image * im, int x, int y)
345{
346    put_part_image(im, x, y, 0, 0, im->Size().x - 1, im->Size().y - 1);
347}
348
349//
350// update_dirty_window()
351// Update the dirty parts of the window
352//
353void update_dirty_window(image *im, int xoff, int yoff)
354{
355    int count;
356    dirty_rect *dr, *q;
357    CHECK(im->m_special); // make sure the image has the ability to contain dirty areas
358    if(im->m_special->keep_dirt == 0)
359    {
360        put_image(im, xoff, yoff);
361    }
362    else
363    {
364        count = im->m_special->dirties.number_nodes();
365        if(!count)
366            return;  // if nothing to update, return
367        dr = (dirty_rect *)(im->m_special->dirties.first());
368        while(count > 0)
369        {
370            put_part_image(im, xoff + dr->dx1, yoff + dr->dy1, dr->dx1, dr->dy1, dr->dx2 + 1, dr->dy2 + 1);
371            q = dr;
372            dr = (dirty_rect *)(dr->next());
373            im->m_special->dirties.unlink(q);
374            delete q;
375            count--;
376        }
377    }
378}
379
380//
381// update_dirty()
382// Update the dirty parts of the image
383//
384void update_dirty(image *im, int xoff, int yoff)
385{
386    update_dirty_window(im, xoff, yoff);
387    update_window_done();
388}
389
390//
391// load()
392// Set the palette
393//
394void palette::load()
395{
396    if(lastl)
397        delete lastl;
398    lastl = copy();
399
400    // Force to only 256 colours.
401    // Shouldn't be needed, but best to be safe.
402    if(ncolors > 256)
403        ncolors = 256;
404
405    SDL_Color colors[ncolors];
406    for(int ii = 0; ii < ncolors; ii++)
407    {
408        colors[ii].r = red(ii);
409        colors[ii].g = green(ii);
410        colors[ii].b = blue(ii);
411    }
412    SDL_SetColors(surface, colors, 0, ncolors);
413    if(window->format->BitsPerPixel == 8)
414        SDL_SetColors(window, colors, 0, ncolors);
415
416    // Now redraw the surface
417    update_window_part(NULL);
418    update_window_done();
419}
420
421//
422// load_nice()
423//
424void palette::load_nice()
425{
426    load();
427}
428
429// ---- support functions ----
430
431void update_window_done()
432{
433#ifdef HAVE_OPENGL
434    // opengl blit complete surface to window
435    if(flags.gl)
436    {
437        // convert color-indexed surface to RGB texture
438        SDL_BlitSurface(surface, NULL, texture, NULL);
439
440        // Texturemap complete texture to surface so we have free scaling
441        // and antialiasing
442        glTexSubImage2D(GL_TEXTURE_2D, 0,
443                        0, 0, texture->w, texture->h,
444                        GL_RGBA, GL_UNSIGNED_BYTE, texture->pixels);
445        glBegin(GL_TRIANGLE_STRIP);
446        glTexCoord2f(texcoord[0], texcoord[1]); glVertex3i(0, 0, 0);
447        glTexCoord2f(texcoord[2], texcoord[1]); glVertex3i(window->w, 0, 0);
448        glTexCoord2f(texcoord[0], texcoord[3]); glVertex3i(0, window->h, 0);
449        glTexCoord2f(texcoord[2], texcoord[3]); glVertex3i(window->w, window->h, 0);
450        glEnd();
451
452        if(flags.doublebuf)
453            SDL_GL_SwapBuffers();
454    }
455#else
456    // swap buffers in case of double buffering
457    // do nothing in case of single buffering
458    if(flags.doublebuf)
459        SDL_Flip(window);
460#endif
461}
462
463void update_window_part(SDL_Rect *rect)
464{
465    // no partial blit's in case of opengl
466    // complete blit + scaling just before flip
467    if (flags.gl)
468        return;
469
470    SDL_BlitSurface(surface, rect, window, rect);
471
472    // no window update needed until end of run
473    if(flags.doublebuf)
474        return;
475
476    // update window part for single buffer
477    if(rect == NULL)
478        SDL_UpdateRect(window, 0, 0, 0, 0);
479    else
480        SDL_UpdateRect(window, rect->x, rect->y, rect->w, rect->h);
481}
Note: See TracBrowser for help on using the repository browser.