3 #include <SDL_opengl.h>
13 void viewport(Display
* display
, GLsizei w
, GLsizei h
, GLsizei bpp
,
14 bool fullscreen
, int aa
=0)
17 SDL_GL_SetAttribute( SDL_GL_RED_SIZE
, bpp
/3 );
18 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE
, bpp
/3 );
19 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE
, bpp
/3 );
20 SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE
, 16 );
21 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER
, 1 );
24 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS
, 1 );
25 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES
, aa
);
28 int flags
= SDL_HWSURFACE
|SDL_OPENGLBLIT
|SDL_RESIZABLE
;
30 flags
|= SDL_FULLSCREEN
;
31 display
->screen
= SDL_SetVideoMode(w
, h
, bpp
, flags
);
32 if(display
->screen
== NULL
)
35 bpp
= display
->screen
->format
->BitsPerPixel
;
36 //printf("%dx%dx%d\n", display->screen->w, display->screen->h, display->screen->format->BitsPerPixel);
41 SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS
, &arg
);
42 printf("SDL_GL_MULTISAMPLEBUFFERS %d\n", arg
);
43 SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES
, &arg
);
44 printf("SDL_GL_MULTISAMPLESAMPLES %d\n", arg
);
48 SDL_WM_SetCaption("cave9 -- 9hells.org", "cave9");
49 SDL_ShowCursor(SDL_DISABLE
);
54 glMatrixMode(GL_PROJECTION
);
56 gluPerspective(45,-w
/(GLfloat
)h
,display
->near_plane
,display
->far_plane
);
60 glClearColor(0,0,0,0);
63 glDepthFunc(GL_LEQUAL
);
64 glEnable(GL_DEPTH_TEST
);
66 glPolygonMode( GL_FRONT
, GL_FILL
);
67 glEnable(GL_CULL_FACE
);
71 glHint(GL_PERSPECTIVE_CORRECTION_HINT
, GL_NICEST
);
72 glShadeModel(GL_SMOOTH
);
73 glEnable(GL_LINE_SMOOTH
);
75 glShadeModel(GL_FLAT
);
76 glHint(GL_PERSPECTIVE_CORRECTION_HINT
, GL_FASTEST
);
81 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
84 glFogi(GL_FOG_MODE
, GL_LINEAR
);
85 GLfloat fog_color
[] = {0,0,0,1};
86 glFogfv(GL_FOG_COLOR
, fog_color
);
87 glFogf(GL_FOG_START
, display
->near_plane
);
88 glFogf(GL_FOG_END
, display
->far_plane
);
93 #ifdef GL_ARB_multisample
94 glEnable(GL_MULTISAMPLE_ARB
);
96 glHint(GL_MULTISAMPLE_FILTER_HINT_NV
,GL_NICEST
);
101 fprintf(stderr
, "SDL ERROR: %s\n", SDL_GetError());
105 void display_world_transform(Display
* display
, Ship
* player
)
107 COPY(display
->cam
, player
->pos
);
108 ADD2(display
->target
, player
->pos
, player
->lookAt
);
109 //display->target[1]=display->target[1]*.5+player->pos[1]*.5;
110 //display->target[2]+=10;
112 display
->cam
[0], display
->cam
[1], display
->cam
[2],
113 display
->target
[0], display
->target
[1], display
->target
[2],
118 void cave_model(Display
* display
, Cave
* cave
, int wire
)
120 for( int i
= 0; i
< SEGMENT_COUNT
-1; ++i
) {
121 int i0
= (cave
->i
+ i
)%SEGMENT_COUNT
;
123 if( (wire
? cave
->gl_wire_list
: cave
->gl_list
)[i0
] == 0 ) {
125 (cave
->gl_wire_list
[i0
] = i0
+ display
->wire_list_start
) :
126 (cave
->gl_list
[i0
] = i0
+ display
->list_start
) ;
128 glNewList( id
, GL_COMPILE
);
130 int i1
= (i0
+ 1)%SEGMENT_COUNT
;
132 glBindTexture(GL_TEXTURE_2D
, display
->texture_id
);
133 glBegin(GL_QUAD_STRIP
);
134 for( int k
= 0; k
<= SECTOR_COUNT
; ++k
) {
136 int k0
= k
%SECTOR_COUNT
;
139 if(i0
==0||i1
==0||k
==3*SECTOR_COUNT
/4)
140 glColor4f(1, 0, 0, 0.5);
142 glColor4f(1, 1, 1, 0.5);
147 (float)(cave
->i
+i
)/SEGMENT_COUNT
,
148 (float)k
/SECTOR_COUNT
);
151 (float)i0
/SEGMENT_COUNT
,
152 1-(float)i0
/SEGMENT_COUNT
,
153 (float)k0
/SECTOR_COUNT
,
156 glVertex3fv(cave
->segs
[i0
][k0
]);
160 ((float)(cave
->i
+i
+1))/SEGMENT_COUNT
,
161 (float)k
/SECTOR_COUNT
);
164 (float)i1
/SEGMENT_COUNT
,
165 1-(float)i1
/SEGMENT_COUNT
,
166 (float)k0
/SECTOR_COUNT
,
169 glVertex3fv(cave
->segs
[i1
][k0
]);
177 glDisable(GL_DEPTH_TEST
);
179 glDisable(GL_TEXTURE_2D
);
181 glEnable(GL_DEPTH_TEST
);
183 glEnable(GL_TEXTURE_2D
);
186 glCallList( (wire
? cave
->gl_wire_list
: cave
->gl_list
)[i0
] );
191 void monolith_model(Display
* display
, Cave
* cave
, Ship
* player
)
193 if(!display
->monoliths
)
198 float w
= MONOLITH_WIDTH
/2;
199 float h
= MONOLITH_HEIGHT
/2;
200 float d
= MONOLITH_DEPTH
;
202 glEnable(GL_DEPTH_TEST
);
204 glDisable(GL_TEXTURE_2D
);
208 glTranslatef( cave
->monolith_x
, cave
->monolith_y
, cave
->segs
[0][0][2] );
209 glRotatef( cave
->monolith_yaw
, 1, 0, 0 );
211 glBegin( GL_QUAD_STRIP
);
212 glVertex3f( +w
, -h
, d
); glVertex3f( -w
, -h
, d
);
213 glVertex3f( +w
, -h
, 0 ); glVertex3f( -w
, -h
, 0 );
214 glVertex3f( +w
, +h
, 0 ); glVertex3f( -w
, +h
, 0 );
215 glVertex3f( +w
, +h
, d
); glVertex3f( -w
, +h
, d
);
219 glVertex3f( -w
, -h
, d
); glVertex3f( -w
, +h
, d
);
220 glVertex3f( -w
, +h
, 0 ); glVertex3f( -w
, -h
, 0 );
222 glVertex3f( +w
, +h
, d
); glVertex3f( +w
, -h
, d
);
223 glVertex3f( +w
, -h
, 0 ); glVertex3f( +w
, +h
, 0 );
229 void ship_model(Display
* display
, Ship
* ship
)
231 if(!display
->cockpit
)
237 float alpha
= (1-MIN(1,(ship
->pos
[2]/MIN_CAVE_RADIUS_DEPTH
)))/8.;
241 float alert_dist
= ship
->radius
*10;
242 float white
= ship
->dist
<= 0 || ship
->dist
> alert_dist
? 1 :
243 1-(alert_dist
- ship
->dist
)/alert_dist
;
247 glDisable(GL_DEPTH_TEST
);
249 glDisable(GL_TEXTURE_2D
);
251 glColor4f(1,white
,white
,alpha
);
253 glTranslatef(0,0,-SHIP_RADIUS
*f
);
254 glCallList( display
->ship_list
);
258 display_world_transform(display
, ship
);
262 ship
->pos
[2]+SHIP_RADIUS
*f
264 glCallList( display
->ship_list
);
268 void render_text(Display
* display
, GLuint id
, const char* text
,
269 float x
, float y
, float w
, float h
,
270 float r
, float g
, float b
)
272 if(text
== NULL
|| text
[0] == '\0')
274 SDL_Color color
= {0xff,0xff,0xff,0xff};
275 SDL_Surface
* label
= TTF_RenderText_Blended(display
->font
, text
, color
);
276 assert(label
!= NULL
);
278 glDisable(GL_DEPTH_TEST
);
280 glEnable(GL_TEXTURE_2D
);
282 glBindTexture(GL_TEXTURE_2D
, id
);
283 gluBuild2DMipmaps(GL_TEXTURE_2D
,
284 GL_RGBA
, label
->w
, label
->h
,
285 GL_RGBA
, GL_UNSIGNED_BYTE
, label
->pixels
);
287 SDL_FreeSurface(label
);
291 glTranslatef(0,0,-2.65); // XXX magic number
292 glBegin(GL_QUAD_STRIP
);
293 glTexCoord2f(0,1); glVertex3f(1-x
*2+w
,1-y
*2-h
,.5);
294 glTexCoord2f(0,0); glVertex3f(1-x
*2+w
,1-y
*2+h
,0);
296 glTexCoord2f(1,1); glVertex3f(1-x
*2-w
,1-y
*2-h
,.5);
297 glTexCoord2f(1,0); glVertex3f(1-x
*2-w
,1-y
*2+h
,0);
302 void display_hud(Display
* display
, Ship
* player
)
304 if(player
->dist
== FLT_MAX
)
307 float max_vel
[3] = { MAX_VEL_X
, MAX_VEL_Y
, MAX_VEL_Z
};
309 log(1+LEN(player
->vel
)-MAX_VEL_Z
) /
310 log(1+LEN(max_vel
)-MAX_VEL_Z
));
316 int score
= (int)player
->pos
[2];
318 #define HUD_TEXT_MAX 80
319 char buf
[HUD_TEXT_MAX
];
320 if(player
->dist
> 0) {
321 snprintf(buf
, HUD_TEXT_MAX
, "velocity %-10s score %9d",
325 if(score
> display
->session_score
)
326 display
->session_score
= score
;
328 snprintf(buf
, HUD_TEXT_MAX
, "velocity %s score %d (%d) - %d",
330 display
->session_score
,
334 if(score
> display
->local_score
) {
335 display
->local_score
= score
;
336 FILE* fp
= fopen(SCORE_FILE
, "w");
338 perror("failed to open score file");
340 fprintf(fp
, "%d", display
->local_score
);
344 if(score
> display
->global_score
) {
345 display
->global_score
= score
;
346 display_net_update(display
);
348 snprintf(buf
, HUD_TEXT_MAX
, "velocity %s score %d (%d/%d/%d)",
350 display
->session_score
,
351 display
->local_score
,
352 display
->global_score
357 float white
= player
->dist
<= 0 ? 1 : 1-vel
;
358 render_text(display
, display
->hud_id
, buf
, .5,.9,1,.2, 1,white
,white
);
361 char display_message_buf
[256];
362 void display_message(Display
* display
, Cave
* cave
, Ship
* player
, const char* buf
)
364 strncpy(display_message_buf
, buf
, sizeof(display_message_buf
)-1);
365 display_message_buf
[sizeof(display_message_buf
)-1] = '\0';
366 display_frame(display
, cave
, player
);
369 void display_start_frame(Display
* display
, float r
, float g
, float b
)
371 glClearColor(r
,g
,b
,1);
372 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
373 glMatrixMode(GL_MODELVIEW
);
377 void display_end_frame(Display
* display
)
381 SDL_GL_SwapBuffers();
384 void display_frame(Display
* display
, Cave
* cave
, Ship
* player
)
386 int hit
= player
->dist
<= SHIP_RADIUS
*1.1;
388 display_start_frame(display
, hit
,0,0);
390 if(!hit
) { // avoid drawing the cave from outside
392 display_world_transform(display
, player
);
393 cave_model(display
, cave
, 0);
394 monolith_model(display
, cave
, player
);
398 ship_model(display
, player
);
399 display_minimap(display
, cave
, player
);
400 display_hud(display
, player
);
401 render_text(display
, display
->msg_id
, display_message_buf
, .5,.5,1,.25, 1,1,1);
403 display_end_frame(display
);
406 GLuint
display_make_ship_list()
408 /* Magic Numbers: It is possible to create a dodecahedron by attaching two pentagons
409 * to each face of a cube. The coordinates of the points are:
410 * (+-x,0, z); (+-1, 1, 1); (0, z, x )
411 * where x = 0.61803398875 and z = 1.61803398875.
414 const double x
= 0.61803398875;
415 const double z
= 1.61803398875;
416 const double n1
= 0.525731112119;
417 const double n2
= 0.850650808354;
419 GLuint ship_list
= glGenLists( SEGMENT_COUNT
);
420 glNewList( ship_list
, GL_COMPILE
);
421 glBegin( GL_LINE_LOOP
);
422 glNormal3d( 0, n1
, n2
);
423 glVertex3d( 0, z
, x
);
424 glVertex3d( -1, 1, 1 );
425 glVertex3d( -x
, 0, z
);
426 glVertex3d( x
, 0, z
);
427 glVertex3d( 1, 1, 1 );
429 glBegin( GL_LINE_LOOP
);
430 glNormal3d( 0, n1
, -n2
);
431 glVertex3d( 0, z
, -x
);
432 glVertex3d( 1, 1, -1 );
433 glVertex3d( x
, 0, -z
);
434 glVertex3d( -x
, 0, -z
);
435 glVertex3d( -1, 1, -1 );
437 glBegin( GL_LINE_LOOP
);
438 glNormal3d( 0, -n1
, n2
);
439 glVertex3d( 0, -z
, x
);
440 glVertex3d( 1, -1, 1 );
441 glVertex3d( x
, 0, z
);
442 glVertex3d( -x
, 0, z
);
443 glVertex3d( -1, -1, 1 );
445 glBegin( GL_LINE_LOOP
);
446 glNormal3d( 0, -n1
, -n2
);
447 glVertex3d( 0, -z
, -x
);
448 glVertex3d( -1, -1, -1 );
449 glVertex3d( -x
, 0, -z
);
450 glVertex3d( x
, 0, -z
);
451 glVertex3d( 1, -1, -1 );
454 glBegin( GL_LINE_LOOP
);
455 glNormal3d( n2
, 0, n1
);
456 glVertex3d( x
, 0, z
);
457 glVertex3d( 1, -1, 1 );
458 glVertex3d( z
, -x
, 0 );
459 glVertex3d( z
, x
, 0 );
460 glVertex3d( 1, 1, 1 );
462 glBegin( GL_LINE_LOOP
);
463 glNormal3d( -n2
, 0, n1
);
464 glVertex3d( -x
, 0, z
);
465 glVertex3d( -1, 1, 1 );
466 glVertex3d( -z
, x
, 0 );
467 glVertex3d( -z
, -x
, 0 );
468 glVertex3d( -1, -1, 1 );
470 glBegin( GL_LINE_LOOP
);
471 glNormal3d( n2
, 0, -n1
);
472 glVertex3d( x
, 0, -z
);
473 glVertex3d( 1, 1, -1 );
474 glVertex3d( z
, x
, 0 );
475 glVertex3d( z
, -x
, 0 );
476 glVertex3d( 1, -1, -1 );
478 glBegin( GL_LINE_LOOP
);
479 glNormal3d( -n2
, 0, -n1
);
480 glVertex3d( -x
, 0, -z
);
481 glVertex3d( -1, -1, -1 );
482 glVertex3d( -z
, -x
, 0 );
483 glVertex3d( -z
, x
, 0 );
484 glVertex3d( -1, 1, -1 );
487 glBegin( GL_LINE_LOOP
);
488 glNormal3d( n1
, n2
, 0 );
489 glVertex3d( z
, x
, 0 );
490 glVertex3d( 1, 1, -1 );
491 glVertex3d( 0, z
, -x
);
492 glVertex3d( 0, z
, x
);
493 glVertex3d( 1, 1, 1 );
495 glBegin( GL_LINE_LOOP
);
496 glNormal3d( n1
, -n2
, 0 );
497 glVertex3d( z
, -x
, 0 );
498 glVertex3d( 1, -1, 1 );
499 glVertex3d( 0, -z
, x
);
500 glVertex3d( 0, -z
, -x
);
501 glVertex3d( 1, -1, -1 );
503 glBegin( GL_LINE_LOOP
);
504 glNormal3d( -n1
, n2
, 0 );
505 glVertex3d( -z
, x
, 0 );
506 glVertex3d( -1, 1, 1 );
507 glVertex3d( 0, z
, x
);
508 glVertex3d( 0, z
, -x
);
509 glVertex3d( -1, 1, -1 );
511 glBegin( GL_LINE_LOOP
);
512 glNormal3d( -n1
, -n2
, 0 );
513 glVertex3d( -z
, -x
, 0 );
514 glVertex3d( -1, -1, -1 );
515 glVertex3d( 0, -z
, -x
);
516 glVertex3d( 0, -z
, x
);
517 glVertex3d( -1, -1, 1 );
525 void display_init(Display
* display
, Args
* args
)
528 memset(display
, 0, sizeof(Display
));
530 if(SDL_Init(SDL_INIT_VIDEO
) != 0) {
531 fprintf(stderr
, "SDL_Init(): %s\n", SDL_GetError());
536 display
->near_plane
= MIN(SEGMENT_LEN
,SHIP_RADIUS
)/4.; // was EPSILON;
537 display
->far_plane
= SEGMENT_COUNT
* SEGMENT_LEN
;
538 SET(display
->cam
, 0,0,0);
539 SET(display
->target
, 0,0,1);
542 int h
= args
->height
;
543 int f
= args
->fullscreen
;
545 #if SDL_VERSION_ATLEAST(1,2,11)
546 const SDL_VideoInfo
* info
= SDL_GetVideoInfo();
547 assert(info
!= NULL
);
556 viewport(display
, w
, h
, args
->bpp
, f
, args
->antialiasing
);
558 display
->list_start
= glGenLists( SEGMENT_COUNT
);
559 display
->wire_list_start
= glGenLists( SEGMENT_COUNT
);
561 if(TTF_Init() != 0) {
562 fprintf(stderr
, "TTF_Init(): %s\n", TTF_GetError());
567 char* font_filename
= FONT_FILE
;
568 int font_size
= args
->antialiasing
? 96 : 48;
569 display
->font
= TTF_OpenFont(font_filename
, font_size
); // FIXME path
570 if(display
->font
== NULL
) {
571 fprintf(stderr
, "TTF_OpenFont(%s): %s\n", font_filename
, TTF_GetError());
575 glGenTextures(1, &display
->hud_id
);
576 glBindTexture(GL_TEXTURE_2D
, display
->hud_id
);
577 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
578 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
579 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
580 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
582 glGenTextures(1, &display
->msg_id
);
583 glBindTexture(GL_TEXTURE_2D
, display
->msg_id
);
584 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
585 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
586 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
587 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
589 display_start_frame(display
, 0,0,0);
590 render_text(display
, display
->msg_id
, "loading cave9", .5,.5,1,.25, 1,1,1);
591 display_end_frame(display
);
593 char* texture_filename
= TEXTURE_FILE
;
595 glGenTextures(1, &display
->texture_id
);
596 glBindTexture(GL_TEXTURE_2D
, display
->texture_id
);
597 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR_MIPMAP_LINEAR
);
598 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
600 SDL_Surface
* texture
= IMG_Load(texture_filename
);
601 if(texture
== NULL
) {
602 fprintf(stderr
, "IMG_Load(%s): %s\n", texture_filename
, IMG_GetError());
606 GLenum err
= gluBuild2DMipmaps(GL_TEXTURE_2D
,
607 GL_RGB
, texture
->w
, texture
->h
,
608 GL_RGB
, GL_UNSIGNED_BYTE
,texture
->pixels
);
610 fprintf(stderr
, "gluBuild2DMipmaps(): %s\n", gluErrorString(err
));
614 SDL_FreeSurface(texture
);
616 display
->ship_list
= display_make_ship_list();
618 display
->monoliths
= args
->monoliths
;
619 display
->cockpit
= args
->cockpit
;
621 display
->session_score
= 0;
623 display
->local_score
= 0;
624 FILE* fp
= fopen(SCORE_FILE
, "r");
626 perror("failed to open score file");
628 fscanf(fp
, "%d", &display
->local_score
);
632 display
->global_score
= 0;
634 if(SDLNet_Init()==-1)
636 fprintf(stderr
, "SDLNet_Init(): %s\n",SDLNet_GetError());
642 display
->udp_sock
= 0;
643 display
->udp_pkt
= NULL
;
644 if(SDLNet_ResolveHost(&addr
,GLOBAL_SCORE_HOST
, GLOBAL_SCORE_PORT
) == -1) {
645 fprintf(stderr
, "SDLNet_ResolveHost(): %s\n", SDLNet_GetError());
647 display
->udp_sock
=SDLNet_UDP_Open(0);
648 if(display
->udp_sock
== 0) {
649 fprintf(stderr
, "SDLNet_UDP_Open(): %s\n", SDLNet_GetError());
650 display_net_finish(display
);
652 if(SDLNet_UDP_Bind(display
->udp_sock
, 0, &addr
) == -1) {
653 fprintf(stderr
, "SDLNet_UDP_Bind(): %s\n", SDLNet_GetError());
654 display_net_finish(display
);
656 display
->udp_pkt
= SDLNet_AllocPacket(GLOBAL_SCORE_LEN
);
657 if(display
->udp_pkt
== NULL
) {
658 display_net_finish(display
);
666 void display_net_update(Display
* display
)
668 if(display
->udp_sock
== 0)
671 snprintf((char*)display
->udp_pkt
->data
,GLOBAL_SCORE_LEN
,"%d",display
->global_score
);
672 display
->udp_pkt
->len
= GLOBAL_SCORE_LEN
;
673 if(SDLNet_UDP_Send(display
->udp_sock
,0,display
->udp_pkt
) == 0) {
674 fprintf(stderr
, "SDLNet_UDP_Send(): %s\n", SDLNet_GetError());
676 SDL_Delay(666); // XXX only wait 666ms for hiscores
677 if(SDLNet_UDP_Recv(display
->udp_sock
,display
->udp_pkt
) == 0) {
678 fprintf(stderr
, "SDLNet_UDP_Recv(%s,%d): %s\n",
679 GLOBAL_SCORE_HOST
, GLOBAL_SCORE_PORT
, SDLNet_GetError());
681 sscanf((char*)display
->udp_pkt
->data
,"%d",&display
->global_score
);
686 void display_net_finish(Display
* display
)
688 if(display
->udp_pkt
!= NULL
){
689 SDLNet_FreePacket(display
->udp_pkt
);
690 display
->udp_pkt
= NULL
;
692 if(display
->udp_sock
!= 0) {
693 SDLNet_UDP_Close(display
->udp_sock
);
694 display
->udp_sock
= 0;
698 void display_minimap(Display
* display
, Cave
* cave
, Ship
* player
)
701 glScalef(.0065,.003,.001);
702 glRotatef(-90,0,1,0);
704 -player
->pos
[0]-1000, // XXX hardcoded
706 -player
->pos
[2]-(SEGMENT_COUNT
-1)*SEGMENT_LEN
/2);
707 cave_model(display
, cave
, 1);
712 // vim600:fdm=syntax:fdn=1: