git-svn-id: https://cave9.googlecode.com/svn/trunk@32 13012bb5-4427-0410-85c5-5d3d33b...
[cave9.git] / src / display.cpp
blobd33d8dc53f91c5c1e2e1e6e5206f9d2ae8246f5b
2 #include <SDL_opengl.h>
3 #include <GL/gl.h>
4 #include <GL/glu.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <math.h>
8 #include <float.h>
9 #include <assert.h>
10 #include "display.h"
12 //#define AA //anti-aliasing
14 void viewport(Display *display, GLsizei w, GLsizei h, GLsizei bpp)
16 if( bpp == 0 )
17 bpp = display->screen->format->BitsPerPixel;
19 // video mode
20 SDL_GL_SetAttribute( SDL_GL_RED_SIZE, bpp/3 );
21 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, bpp/3 );
22 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, bpp/3 );
23 SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
24 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
25 #ifdef AA
26 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
27 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 4 );
28 #endif
29 display->screen = SDL_SetVideoMode(w, h, bpp, SDL_HWSURFACE|SDL_OPENGLBLIT|SDL_RESIZABLE);
30 if(display->screen == NULL) goto error;
31 //printf("%dx%dx%d\n", display->screen->w, display->screen->h, display->screen->format->BitsPerPixel);
33 #ifdef AA
34 int arg;
35 SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &arg );
36 //printf("SDL_GL_MULTISAMPLEBUFFERS %d\n", arg);
37 SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &arg );
38 //printf("SDL_GL_MULTISAMPLESAMPLES %d\n", arg);
39 #endif
41 // projection
42 glViewport(0,0,w,h);
44 glMatrixMode(GL_PROJECTION);
45 glLoadIdentity();
46 gluPerspective(45,-w/(GLfloat)h,display->near_plane,display->far_plane);
49 // settings
50 glClearColor(0,0,0,0);
51 glClearDepth(1);
52 glDepthFunc(GL_LEQUAL);
53 glEnable(GL_DEPTH_TEST);
54 //glEnable(GL_CULL_FACE);
55 //glCullFace(GL_BACK);
56 glShadeModel(GL_SMOOTH);
57 //glShadeModel(GL_FLAT);
58 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
59 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
61 #if 1
63 glFogi(GL_FOG_MODE, GL_LINEAR);
64 GLfloat fog_color[] = {0,0,0,1};
65 glFogfv(GL_FOG_COLOR, fog_color);
66 glFogf(GL_FOG_START, display->near_plane);
67 glFogf(GL_FOG_END, display->far_plane);
68 glEnable(GL_FOG);
70 #endif
72 #ifdef AA
73 #ifndef GL_ARB_multisample
74 glHint(GL_MULTISAMPLE_FILTER_HINT_NV,GL_NICEST);
75 #endif
76 glEnable(GL_MULTISAMPLE_ARB);
77 #endif
79 return;
80 error:
81 fprintf(stderr, "SDL ERROR: %s\n", SDL_GetError());
82 exit(1);
85 void cave_model(Display *display, Cave *cave)
87 cave->ymin = FLT_MAX;
88 cave->ymax = FLT_MIN;
90 int i, j;
91 glEnable(GL_BLEND);
92 for( j = 0; j < CAVE_DEPTH-1; ++j ) {
93 int j0 = (cave->i + j)%CAVE_DEPTH;
94 if( cave->gl_list[j0] != 0 ) {
95 glCallList( cave->gl_list[j0] );
97 else {
98 cave->gl_list[j0] = j0 + display->list_start;
99 glNewList( cave->gl_list[j0], GL_COMPILE_AND_EXECUTE );
101 int j1 = (j0 + 1)%CAVE_DEPTH;
102 glBegin(GL_TRIANGLE_STRIP);
103 for( i = 0; i <= N_SEGS; ++i ) {
105 int i0 = i%N_SEGS;
107 glColor4f(.4, .6*i0/N_SEGS, .9*j1/CAVE_DEPTH, 1);
108 glVertex3fv(cave->segs[j0][i0]);
110 glColor4f(.6, .6*i0/N_SEGS, .9*(1-j0/CAVE_DEPTH), 1);
111 glVertex3fv(cave->segs[j1][i0]);
113 if(cave->segs[j][i0][1] < cave->ymin)
114 cave->ymin = cave->segs[j][i0][1];
115 if(cave->segs[j][i0][1] > cave->ymax)
116 cave->ymax = cave->segs[j][i0][1];
118 glEnd();
120 glEndList();
123 glDisable(GL_BLEND);
127 void ship_model(Ship *ship)
131 void render_text(Display *display, const char *text, float x, float y)
133 if(text == NULL || text[0] == '\0')
134 return;
135 #ifdef USE_TTF
136 SDL_Color color = {0xff,0xff,0xff,0xff};
137 SDL_Surface *label = TTF_RenderText_Blended(display->font, text, color);
138 assert(label != NULL);
140 display->rect[display->rect_n].w = label->w;
141 display->rect[display->rect_n].h = label->h;
142 display->rect[display->rect_n].x = (int)(x*display->screen->w - .5*label->w);
143 display->rect[display->rect_n].y = (int)(y*display->screen->h - .5*label->h);
145 SDL_FillRect(display->screen, &display->rect[display->rect_n],
146 SDL_MapRGBA(display->screen->format, 0x00,0x00,0x80,0xff));
147 SDL_BlitSurface(label, NULL, display->screen, &display->rect[display->rect_n]);
149 SDL_FreeSurface(label);
150 ++display->rect_n;
151 #endif
154 void display_hud(Display *display, Ship *player)
156 #define HUD_TEXT_MAX 80
157 char buf[HUD_TEXT_MAX];
158 float wow_factor = 20.0;
159 snprintf(buf, HUD_TEXT_MAX, "collision %.1f velocity %.2fKm/h score %.1f",
160 player->dist, wow_factor*LEN(player->vel), player->pos[2]);
162 #ifdef USE_TTF
163 render_text(display, buf, .5, .95);
164 #else
165 static Uint32 last_hud_print = 0;
166 Uint32 now = SDL_GetTicks();
167 if( now - last_hud_print >= 200 ) {
168 last_hud_print = now;
169 printf("\r%s", buf);
170 fflush(stdout);
172 #endif
175 char display_message_buf[256];
176 void display_message(Display *display, Cave *cave, Ship *player, const char *buf)
178 strncpy(display_message_buf, buf, sizeof(display_message_buf)-1);
179 display_message_buf[sizeof(display_message_buf)-1] = '\0';
180 #ifdef USE_TTF
181 display_frame(display, cave, player);
182 #else
183 printf("\n%s\n", display_message_buf);
184 #endif
187 void display_start_frame(Display *display, Ship *player)
189 display->rect_n = 0;
190 COPY(display->cam, player->pos);
191 SET(display->target, player->pos[0], player->pos[1], player->pos[2]+1);
192 //ADD2(display->target, player->pos, player->vel);
194 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
195 glMatrixMode(GL_MODELVIEW);
196 glLoadIdentity();
197 #if 1
198 gluLookAt(
199 display->cam[0], display->cam[1], display->cam[2],
200 display->target[0], display->target[1], display->target[2],
201 0,1,0
203 #else // de lado
204 gluLookAt(
205 display->cam[0], display->cam[1], display->cam[2],
206 display->target[0], display->target[1], display->target[2],
207 0,1,0
209 #endif
212 void display_end_frame(Display *display)
214 glFinish();
216 SDL_UpdateRects(display->screen, display->rect_n, display->rect); // only update 2D
218 SDL_GL_SwapBuffers(); // update 3d
221 void display_frame(Display *display, Cave *cave, Ship *player)
223 display_start_frame(display, player);
224 cave_model(display, cave);
225 ship_model(player);
226 display_hud(display, player);
227 display_minimap(display, cave, player);
228 render_text(display, display_message_buf, .5, .5);
229 display_end_frame(display);
232 void display_init(Display *display)
235 if(SDL_Init(SDL_INIT_VIDEO) != 0) {
236 fprintf(stderr, "SDL_Init(): %s\n", SDL_GetError());
237 exit(1);
239 atexit(SDL_Quit);
241 display->rect_n = 0;
242 display->near_plane = SHIP_RADIUS/2.; // was EPSILON;
243 display->far_plane = CAVE_DEPTH * SEGMENT_LEN;
244 SET(display->cam,0,0,0);
245 SET(display->target,0,0,1);
247 viewport(display,640,480,16);
248 display->list_start = glGenLists( CAVE_DEPTH );
250 #ifdef USE_TTF
251 if(TTF_Init() != 0) {
252 fprintf(stderr, "TTF_Init(): %s\n", TTF_GetError());
253 exit(1);
255 atexit(TTF_Quit);
257 char* font_filename = "font.pcf";
258 int font_size = 16;
259 display->font = TTF_OpenFont(font_filename, font_size); // FIXME path
260 if(display->font == NULL) {
261 fprintf(stderr, "TTF_OpenFont(%s): %s\n", font_filename, TTF_GetError());
262 exit(1);
264 #endif
266 display->minimap = SDL_CreateRGBSurface( SDL_SWSURFACE,
267 CAVE_DEPTH*2, CAVE_DEPTH*2,
268 display->screen->format->BitsPerPixel,
269 0, 0, 0, 0);
270 assert( display->minimap != NULL );
273 void display_minimap(Display *display, Cave *cave, Ship *player)
275 SDL_FillRect( display->minimap, 0, 0 );
277 // cave
278 int i;
279 for( i = 0; i < CAVE_DEPTH; ++i ) {
280 int j = ((i+cave->i) % CAVE_DEPTH);
281 float y1 = cave->segs[j][1*N_SEGS/4][1];
282 float y0 = cave->segs[j][3*N_SEGS/4][1];
283 SDL_Rect rect;
284 rect.x = i*2;
285 rect.w = 2-1;
286 rect.y = (int)(cave->ymax - y1);
287 rect.h = (int)(y1 - y0);
288 SDL_FillRect( display->minimap, &rect, 0xffffffff );
291 { // player ship
292 SDL_Rect rect;
293 rect.x = (int)(2*(player->pos[2] - cave->segs[cave->i][0][2]));
294 rect.x = 2; //HACK: smooth. TODO: properly smooth cave and ship.
295 rect.w = 2;
296 rect.y = (int)(cave->ymax - player->pos[1]);
297 rect.h = 2;
298 SDL_FillRect( display->minimap, &rect, 0 );
302 // blit minimap to screen
303 SDL_Rect rect;
304 rect.x = 0;
305 rect.w = display->minimap->w;
306 rect.y = 0;
307 rect.h = (int)(cave->ymax - cave->ymin);
309 SDL_Rect *d_rect = &display->rect[display->rect_n++];
310 d_rect->x = display->screen->w - display->minimap->w;
311 d_rect->w = display->minimap->w;
312 d_rect->y = 0;
313 d_rect->h = (int)(cave->ymax - cave->ymin);
314 SDL_BlitSurface(display->minimap, &rect, display->screen, d_rect);
317 // vim600:fdm=syntax:fdn=1: