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

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

core: Get rid of mostly useless headers, move endianness handling to
common.h (and rewrite functions so that they do not need the SDL headers)
and move a few functions out of sdlport's video.cpp. These functions
were in the original video.cpp (which reappears) and shouldn't be part
of the SDL port.

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