📄 sscroll.c
字号:
/*------------------------------------------------------------ Smooth Scrolling------------------------------------------------------------ * Using OpenGL and sub-pixel accurate rendering. * Map editor included. :-) * * Copyright (c) David Olofson <david@olofson.net>, 2002 * * This software is released under the terms of the GPL. */#include <stdlib.h>#include <string.h>#include <math.h>#include "SDL.h"#if HAS_SDL_OPENGL_H#include "SDL_opengl.h"#else#ifdef WIN32#include <windows.h>#endif#if defined(__APPLE__) && defined(__MACH__)#include <OpenGL/gl.h>#include <OpenGL/glu.h>#else#include <GL/gl.h>#include <GL/glu.h>#endif#endif/* Screen size (unscaled) */#define SCREEN_W 320#define SCREEN_H 240/* Tile size */#define TILE_W 32#define TILE_H 32/* Tile palette size (pixels) */#define PALETTE_W 256#define PALETTE_H 256/* Tile palette size (tiles) */#define PALETTE_TW (PALETTE_W / TILE_W)#define PALETTE_TH (PALETTE_H / TILE_H)/* Map size (tiles) */#define MAP_W 32#define MAP_H 16/*------------------------------------------------ Common stuff------------------------------------------------*/void (*video_draw_tile)(float x, float y, int tile);Uint32 (*video_map_rgb)(Uint8 r, Uint8 g, Uint8 b);void (*video_fillrect)(SDL_Rect *r, Uint32 color);void (*video_flip)(void);void (*video_close)(void);unsigned char *map = NULL;int flags = 0; /* SDL video flags */int bpp = 0; /* Preferred screen bpp */int scale = -1; /* Screen scale factor */int mscale; /* Mouse scale factor */int screen_w, screen_h; /* Actual screen size */int vscreen_w, vscreen_h; /* Virtual screen size *//*------------------------------------------------ SDL mode------------------------------------------------*/SDL_Surface *screen = NULL;SDL_Surface *tiles = NULL;void draw_tile_sdl(float x, float y, int tile){ SDL_Rect source_rect, dest_rect; source_rect.x = tile % PALETTE_TW * TILE_W; source_rect.y = tile / PALETTE_TW * TILE_H; source_rect.w = TILE_W; source_rect.h = TILE_H; dest_rect.x = (int)floor(x); dest_rect.y = (int)floor(y); SDL_BlitSurface(tiles, &source_rect, screen, &dest_rect);}Uint32 map_rgb_sdl(Uint8 r, Uint8 g, Uint8 b){ return SDL_MapRGB(screen->format, r, g, b);}void fillrect_sdl(SDL_Rect *r, Uint32 color){ SDL_FillRect(screen, r, color);}void flip_sdl(void){ SDL_Flip(screen);}void close_sdl(void){ SDL_FreeSurface(tiles); SDL_Quit();}int init_sdl(void){ SDL_Surface *tmp = NULL; video_draw_tile = draw_tile_sdl; video_map_rgb = map_rgb_sdl; video_fillrect = fillrect_sdl; video_flip = flip_sdl; video_close = close_sdl; screen = SDL_SetVideoMode(screen_w, screen_h, bpp, flags); if(!screen) { fprintf(stderr, "Failed to open screen!\n"); exit(-1); } tmp = SDL_LoadBMP("tiles.bmp"); if(!tmp) { fprintf(stderr, "Could not load graphics!\n"); return -1; } tiles = SDL_DisplayFormat(tmp); if(!tiles) { fprintf(stderr, "Could not convert graphics!\n"); return -1; } SDL_FreeSurface(tmp); return 0;}/*------------------------------------------------ OpenGL mode------------------------------------------------*/GLint gl_tiles;/* OpenGL "state optimizer" hack from glSDL */static struct{ int do_blend; int do_texture; GLint texture; GLenum sfactor, dfactor;} glstate;static void gl_reset(void){ glstate.do_blend = -1; glstate.do_blend = -1; glstate.texture = -1; glstate.sfactor = 0xffffffff; glstate.dfactor = 0xffffffff;}static __inline__ void gl_do_blend(int on){ if(glstate.do_blend == on) return; if(on) glEnable(GL_BLEND); else glDisable(GL_BLEND); glstate.do_blend = on;}static __inline__ void gl_do_texture(int on){ if(glstate.do_texture == on) return; if(on) glEnable(GL_TEXTURE_2D); else glDisable(GL_TEXTURE_2D); glstate.do_texture = on;}static __inline__ void gl_blendfunc(GLenum sfactor, GLenum dfactor){ if((sfactor == glstate.sfactor) && (dfactor == glstate.dfactor)) return; glBlendFunc(sfactor, dfactor); glstate.sfactor = sfactor; glstate.dfactor = dfactor;}static __inline__ void gl_texture(GLuint tx){ if(tx == glstate.texture) return; glBindTexture(GL_TEXTURE_2D, tx); glstate.texture = tx;}void draw_tile_gl(float x, float y, int tile){ float tx1 = (float)(tile % PALETTE_TW) / PALETTE_TW; float ty1 = (float)(tile / PALETTE_TH) / PALETTE_TH; float tx2 = tx1 + ((float)TILE_W / PALETTE_W); float ty2 = ty1 + ((float)TILE_H / PALETTE_H); float x1 = x; float y1 = y; float x2 = x + TILE_W; float y2 = y + TILE_H; gl_do_texture(1); gl_do_blend(0); gl_texture(gl_tiles); glBegin(GL_QUADS); glColor4ub(255, 255, 255, 255); glTexCoord2f(tx1, ty1); glVertex2f(x1, y1); glTexCoord2f(tx2, ty1); glVertex2f(x2, y1); glTexCoord2f(tx2, ty2); glVertex2f(x2, y2); glTexCoord2f(tx1, ty2); glVertex2f(x1, y2); glEnd();}Uint32 map_rgb_gl(Uint8 r, Uint8 g, Uint8 b){ return r<<16 | g<<8 | b;}void fillrect_gl(SDL_Rect *r, Uint32 color){ int dx1, dy1, dx2, dy2; gl_do_texture(0); gl_do_blend(0); if(!r) r = &screen->clip_rect; dx1 = r->x; dy1 = r->y; dx2 = dx1 + r->w; dy2 = dy1 + r->h; glBegin(GL_QUADS); glColor3ub((color>>16) & 255, (color>>8) & 255, color & 255); glVertex2i(dx1, dy1); glVertex2i(dx2, dy1); glVertex2i(dx2, dy2); glVertex2i(dx1, dy2); glEnd();}void flip_gl(void){ SDL_GL_SwapBuffers();}void close_gl(void){ glDeleteTextures(1, &gl_tiles); SDL_Quit();}int init_gl(void){ SDL_Surface *tmp, *tmp2; GLint gl_doublebuf; GLint maxtexsize; video_draw_tile = draw_tile_gl; video_map_rgb = map_rgb_gl; video_fillrect = fillrect_gl; video_flip = flip_gl; video_close = close_gl; flags |= SDL_OPENGL; gl_doublebuf = flags & SDL_DOUBLEBUF; if(bpp == 15) { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); } if(bpp == 16) { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); } else if(bpp >= 24) { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); } if(bpp) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, bpp); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, gl_doublebuf); screen = SDL_SetVideoMode(screen_w, screen_h, bpp, flags); if(!screen) { fprintf(stderr, "Failed to open screen!\n"); return -1; } /* * Just because my driver f*cks up if there's console * output when it's messing with textures... :-( */ SDL_Delay(1000); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize); if(maxtexsize < 256) { fprintf(stderr, "Need at least 256x256 textures!\n"); SDL_Quit(); return -1; } tmp = SDL_LoadBMP("tiles.bmp"); if(!tmp) { fprintf(stderr, "Could not load graphics!\n"); SDL_Quit(); return -1; } tmp2 = SDL_CreateRGBSurface(SDL_SWSURFACE, 256, 256, 24,#if SDL_BYTEORDER == SDL_BIG_ENDIAN 0x00ff0000, 0x0000ff00, 0x000000ff, 0);#else 0x000000ff, 0x0000ff00, 0x00ff0000, 0);#endif if(!tmp2) { fprintf(stderr, "Failed to make texture from graphics!\n"); SDL_FreeSurface(tmp); SDL_Quit(); return -1; } SDL_BlitSurface(tmp, NULL, tmp2, NULL); SDL_FreeSurface(tmp); glGenTextures(1, &gl_tiles); glBindTexture(GL_TEXTURE_2D, gl_tiles); glPixelStorei(GL_UNPACK_ROW_LENGTH, tmp2->pitch / tmp2->format->BytesPerPixel); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, tmp2->w, tmp2->h, 0, GL_RGB, GL_UNSIGNED_BYTE, tmp2->pixels); glFlush(); SDL_FreeSurface(tmp2); /* * Set up OpenGL for 2D rendering. */ glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glViewport(0, 0, screen->w, screen->h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, vscreen_w, vscreen_h, 0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, 0.0f); return 0;}/*------------------------------------------------ Common functions------------------------------------------------*/int maxx, maxy;float xpos = 0.0;float ypos = 0.0;float sx = 30.0;float sy = 30.0;void video_bounce(float dt){ int maxx = MAP_W * TILE_W - vscreen_w; int maxy = MAP_H * TILE_H - vscreen_h; if(xpos >= maxx) { sx = -sx; xpos = maxx * 2 - xpos; } else if(xpos <= 0) { sx = -sx; xpos = -xpos; } if(ypos >= maxy) { sy = -sy; ypos = maxy * 2 - ypos; } else if(ypos <= 0) { sy = -sy; ypos = -ypos; }}void video_limit(float dt){ if(xpos >= maxx) xpos = maxx; else if(xpos < 0) xpos = 0; if(ypos >= maxy) ypos = maxy; else if(ypos < 0) ypos = 0;}void video_render(void){ int map_x, map_y, map_x_loop; float fine_x, fine_y; float x, y; map_x = (int)xpos / TILE_W; map_y = (int)ypos / TILE_H; fine_x = (xpos / TILE_W - floor(xpos / TILE_W)) * TILE_W; fine_y = (ypos / TILE_H - floor(ypos / TILE_H)) * TILE_H; for (y = -fine_y; y < vscreen_h; y += TILE_H) { map_x_loop = map_x; for (x = -fine_x; x < vscreen_w; x += TILE_W) { if((map_y < MAP_H) && (map_x_loop < MAP_W)) video_draw_tile(x, y, map[ map_y * MAP_W + map_x_loop++]); else video_draw_tile(x, y, 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -