naev 0.11.5
intro.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
12#include "SDL.h"
13
14#include "naev.h"
17#include "intro.h"
18
19#include "array.h"
20#include "conf.h"
21#include "font.h"
22#include "log.h"
23#include "menu.h"
24#include "music.h"
25#include "ndata.h"
26#include "nstring.h"
27#include "toolkit.h"
28
29#define INTRO_SPEED 30.
30#define SIDE_MARGIN 100.
31#define IMAGE_WIDTH 300.
34typedef struct intro_img_t_ {
35 glTexture *tex; /* Image. */
36 double x, y, w, h; /* Position. */
37 glColour c; /* Alpha channel for fading. */
38 double fade_rate; /* Positive for fade-in, negative for fade-out. */
40
42typedef enum intro_opcode_t_ {
47
49typedef struct intro_cmd_t_ {
50 intro_opcode_t opcode;
51 const char *operand;
53
54/*
55 * State.
56 */
57static intro_cmd_t *intro_cmds = NULL;
58static char *intro_buf = NULL;
60static int has_side_gfx = 0; /* Determines how wide to make the text. */
61
62/*
63 * Prototypes.
64 */
65static int intro_load( const char *text );
66static void intro_cleanup (void);
67static int intro_event_handler( int *stop, double *offset, double *vel );
68static void initialize_image( intro_img_t *img );
69static void load_image( intro_img_t *img, const char *img_file );
70static void intro_fade_image_in( intro_img_t *side, intro_img_t *transition, const char *img_file );
71static int intro_draw_text( char **const sb_list, int sb_size, int sb_index, double offset, double line_height );
72
76static int intro_load( const char *text )
77{
78 size_t intro_size;
79 char *cur_line, *rest_of_file;
80
81 has_side_gfx = 0;
82
83 /* Load text. */
84 intro_buf = ndata_read( text, &intro_size );
85
86 /* Create intro font. */
87 gl_fontInit( &intro_font, _(FONT_MONOSPACE_PATH), conf.font_size_intro, FONT_PATH_PREFIX, 0 );
88
90 rest_of_file = intro_buf;
91 while (rest_of_file) {
92 cur_line = rest_of_file;
93 rest_of_file = strchr(cur_line, '\n');
94 /* If there's a next line, split the string and point rest_of_file to it. */
95 if (rest_of_file != NULL) {
96 /* Check for CRLF endings -- if present, zero both parts. */
97 if (rest_of_file > cur_line && *(rest_of_file-1) == '\r')
98 *(rest_of_file-1) = '\0';
99 *rest_of_file++ = '\0';
100 }
101
102 if (strncmp( cur_line, "[fadein ", 8 ) == 0) {
104 array_back( intro_cmds ).operand = &cur_line[8];
105 /* Zap the closing square-bracket. */
106 cur_line[strlen( cur_line ) - 1] = '\0';
107 /* Mark that there are graphics. */
108 has_side_gfx = 1;
109 }
110 else if (strncmp( cur_line, "[fadeout]", 9 ) == 0)
112 else {
113 array_grow( &intro_cmds ).opcode = INTRO_TEXT;
114 /* Translate the line if it's not the empty string. */
115 array_back( intro_cmds ).operand = (cur_line[0] == '\0' ? cur_line : _(cur_line));
116 }
117 }
118
119 return 0;
120}
121
125static void intro_cleanup (void)
126{
127 /* Free memory. */
129 intro_cmds = NULL;
130 free(intro_buf);
131 intro_buf = NULL;
133}
134
140static void initialize_image( intro_img_t *img )
141{
142 img->tex = NULL;
143 img->c.r = 1.0;
144 img->c.g = 1.0;
145 img->c.b = 1.0;
146 img->c.a = 1.0;
147 img->fade_rate = 0.0;
148}
149
156static void load_image( intro_img_t *img, const char *img_file )
157{
158 img->tex = gl_newImage( img_file, 0 );
159 img->w = MIN( img->tex->w, IMAGE_WIDTH );
160 img->h = img->tex->h * img->w / img->tex->w;
161 img->x = (IMAGE_WIDTH + SIDE_MARGIN - img->w) / 2.0;
162 img->y = (double)SCREEN_H / 2.0 - (img->h / 2.0);
163 img->c.a = 0.0;
164 img->fade_rate = 0.1;
165}
166
174static void intro_fade_image_in( intro_img_t *side, intro_img_t *transition,
175 const char *img_file )
176{
177 if (NULL == side->tex)
178 load_image( side, img_file ); /* Simple fade-in. */
179 else {
180 /*
181 * Transition or on-deck. The difference is whether one image is
182 * replacing the other (transition), or whether the first must fade out
183 * completely before the second comes in (on-deck).
184 *
185 * We can determine which is the case by seeing whether [fadeout] has been
186 * called. I.e., is side->fade_rate < 0?
187 */
188 if (NULL != transition->tex) {
189 /* Scrolling is happening faster than fading... */
190 WARN( _("Intro scrolling too fast!") );
191 gl_freeTexture( transition->tex );
192 }
193 load_image( transition, img_file );
194 if (side->fade_rate < 0.0)
195 transition->fade_rate = 0.0; /* put an image on deck. */
196 else {
197 /* transition. */
198 side->fade_rate = -0.1; /* begin fading out. */
199 side->c.a = 0.99;
200 }
201 }
202}
203
210static int intro_event_handler( int *stop, double *offset, double *vel )
211{
212 SDL_Event event; /* user key-press, mouse-push, etc. */
213 while (SDL_PollEvent(&event)) {
214 if (event.type == SDL_QUIT) {
215 if (naev_isQuit() || menu_askQuit()) {
216 naev_quit();
217 return 1;
218 }
219 }
220
221 if (event.type == SDL_WINDOWEVENT &&
222 event.window.event == SDL_WINDOWEVENT_RESIZED) {
223 naev_resize();
224 continue;
225 }
226
227 if (event.type != SDL_KEYDOWN)
228 continue;
229
230 /* Escape skips directly. */
231 if (event.key.keysym.sym == SDLK_ESCAPE) {
232 *stop = 1;
233 break;
234 }
235
236 /* Slow down the text. */
237 else if (event.key.keysym.sym == SDLK_UP) {
238 *vel -= 8.0;
239 if (*vel < 0.0)
240 *vel = 0.0;
241 }
242
243 /* Speed up the text. */
244 else if (event.key.keysym.sym == SDLK_DOWN) {
245 *vel += 8.0;
246 if (*vel > 100.0)
247 *vel = 100.0;
248 }
249
250 /* Jump down. */
251 else if ((event.key.keysym.sym == SDLK_SPACE) ||
252 (event.key.keysym.sym == SDLK_RETURN))
253 *offset += 100;
254
255 /* Jump up. */
256 else if (event.key.keysym.sym == SDLK_BACKSPACE)
257 *offset -= 100;
258
259 /* User is clearly flailing on keyboard. */
260 else
261 *vel = 16.;
262 }
263 return 0;
264}
265
274static int intro_draw_text( char **const sb_list, int sb_size, int sb_index, double offset, double line_height )
275{
276 double x, y; /* render position. */
277 int i;
278 register int stop = 1;
279
280 x = SIDE_MARGIN;
281 if (has_side_gfx)
282 x += IMAGE_WIDTH;
283
284 i = sb_index;
285 y = SCREEN_H + offset - line_height;
286 do {
287 if ( sb_list[ i ] != NULL ) {
288 stop = 0;
289 gl_printRaw( &intro_font, x, y, &cFontGreen, -1, sb_list[ i ] );
290 }
291
292 y -= line_height;
293 i = ( i + 1 ) % sb_size;
294 } while ( i != sb_index );
295
296 return stop;
297}
298
306int intro_display( const char *text, const char *mus )
307{
308 double offset; /* distance from bottom of the top line. */
309 double line_height; /* # pixels per line. */
310 int lines_per_screen; /* max appearing lines on the screen. */
311 char ** sb_arr; /* array of lines to render. */
312 int sb_index; /* Position in the line array. */
313 double vel = 16.; /* velocity: speed of text. */
314 int stop = 0; /* stop the intro. */
315 unsigned int tcur, tlast, tlag;/* timers. */
316 double delta; /* time diff from last render to this one. */
317 int cmd_index = 0; /* index into the big list of intro lines. */
318 intro_img_t side_image; /* image to go along with the text. */
319 intro_img_t transition; /* image for transitioning. */
320 glPrintLineIterator iter; /* the renderable lines coming from the current text directive. */
321
322 /* Load the introduction. */
323 if (intro_load(text) < 0)
324 return -1;
325
326 /* Change music to intro music. */
327 if (mus != NULL)
328 music_choose(mus);
329
330 /* We need to clear key repeat to avoid infinite loops. */
332
333 /* Do a few calculations to figure out how many lines can be present on the
334 screen at any given time. */
335 line_height = (double)intro_font.h * 1.3;
336 lines_per_screen = (int)(SCREEN_H / line_height + 1.5); /* round up + 1 */
337
338 /* Initialize the lines. */
339 gl_printLineIteratorInit( &iter, &intro_font, "", SCREEN_W - 2*SIDE_MARGIN - IMAGE_WIDTH );
340 (void) gl_printLineIteratorNext( &iter );
341 sb_arr = calloc( lines_per_screen, sizeof( char * ) );
342 sb_index = 0;
343
344 /* Force the first line to be loaded immediately. */
345 offset = line_height;
346
347 /* Unset the side image. */
348 initialize_image( &side_image );
349 initialize_image( &transition );
350
351 tlast = SDL_GetTicks();
352 while (!stop) {
353 tcur = SDL_GetTicks();
354 delta = (double)(tcur - tlast) / 1000.;
355 tlast = tcur;
356
357 /* Increment position. */
358 offset += vel * delta;
359 while (! (offset < line_height)) {
360 /* One line has scrolled off, and another one on. */
361 if (gl_printLineIteratorNext( &iter )) {
362 free( sb_arr[sb_index] );
363 sb_arr[sb_index] = strndup( &iter.text[iter.l_begin], iter.l_end - iter.l_begin );
364 offset -= line_height;
365 sb_index = ( sb_index + 1 ) % lines_per_screen;
366 }
367 else if (cmd_index < array_size(intro_cmds)) {
368 switch (intro_cmds[cmd_index].opcode) {
369 case INTRO_TEXT:
370 gl_printLineIteratorInit( &iter, &intro_font, intro_cmds[cmd_index].operand, iter.width );
371 break;
372 case INTRO_FADEIN:
373 intro_fade_image_in( &side_image, &transition, intro_cmds[cmd_index].operand );
374 break;
375 case INTRO_FADEOUT:
376 if (NULL == side_image.tex) {
377 WARN(_("Tried to fade out without an image.") );
378 break;
379 }
380 side_image.fade_rate = -0.1;
381 side_image.c.a = 0.99;
382 break;
383 }
384 ++cmd_index;
385 } else {
386 free( sb_arr[sb_index] );
387 sb_arr[sb_index] = NULL;
388 offset -= line_height;
389 sb_index = ( sb_index + 1 ) % lines_per_screen;
390 }
391 } /* while (offset > line_height) */
392
393 /* Fade the side image. */
394 if (side_image.tex != NULL && side_image.c.a < 1.0) {
395 side_image.c.a += delta * vel * side_image.fade_rate;
396
397 if (transition.tex != NULL && transition.fade_rate > 0.0)
398 transition.c.a += delta * vel * transition.fade_rate;
399
400 if (side_image.c.a > 1.0) {
401 /* Faded in... */
402 side_image.c.a = 1.0;
403 side_image.fade_rate = 0.0;
404 }
405 else if (side_image.c.a < 0.0) {
406 /* Faded out... */
407 gl_freeTexture( side_image.tex );
408 if (transition.tex != NULL) {
409 side_image.tex = transition.tex;
410 side_image.c.a = transition.c.a;
411 side_image.w = transition.w;
412 side_image.h = transition.h;
413 side_image.y = transition.y;
414 side_image.fade_rate = 0.1;
415 transition.tex = NULL;
416 transition.c.a = 1.0;
417 }
418 else {
419 side_image.c.a = 1.0;
420 side_image.tex = NULL;
421 side_image.fade_rate = 0.0;
422 }
423 }
424 }
425
426 /* Clear stuff. */
427 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
428
429 /* Only thing we actually care about updating is music. */
430 music_update( delta );
431
432 /* Draw text. */
433 stop = intro_draw_text( sb_arr, lines_per_screen, sb_index, offset, line_height );
434
435 if (NULL != side_image.tex)
436 /* Draw the image next to the text. */
437 gl_renderScale( side_image.tex, side_image.x, side_image.y,
438 side_image.w, side_image.h, &side_image.c );
439
440 if (NULL != transition.tex && transition.c.a > 0.0)
441 /* Draw the image in transition. */
442 gl_renderScale( transition.tex, transition.x, transition.y,
443 transition.w, transition.h, &transition.c );
444
445 /* Display stuff. */
446 SDL_GL_SwapWindow( gl_screen.window );
447
448 tlag = SDL_GetTicks() - tcur;
449 if (tlag < 25) /* No need to burn CPU. Note: swapping may involve a wait for vblank; 25 is 1.5 frames @60fps. */
450 SDL_Delay( 25 - tlag );
451
452 /* Handle user events. */
453 if (intro_event_handler( &stop, &offset, &vel ))
454 break;
455
456 } /* while (!stop) */
457
458 /* free malloc'd memory. */
459 free( sb_arr );
460 gl_freeTexture( side_image.tex );
461 gl_freeTexture( transition.tex );
462
463 /* Stop music, normal music will start shortly after. */
464 music_stop(0);
465
466 /* Clean up after the introduction. */
468
469 return 0;
470}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_back(ptr_array)
Returns the last element in the array.
Definition array.h:216
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
int gl_printLineIteratorNext(glPrintLineIterator *iter)
Updates iter with the next line's information.
Definition font.c:526
void gl_printRaw(const glFont *ft_font, double x, double y, const glColour *c, double outlineR, const char *text)
Prints text on screen.
Definition font.c:617
void gl_freeFont(glFont *font)
Frees a loaded font. Caution: its glFontStash still has a slot in avail_fonts. At the time of writing...
Definition font.c:1723
void gl_printLineIteratorInit(glPrintLineIterator *iter, const glFont *ft_font, const char *text, int width)
Initialize an iterator object for breaking text into lines.
Definition font.c:506
int gl_fontInit(glFont *font, const char *fname, const unsigned int h, const char *prefix, unsigned int flags)
Initializes a font.
Definition font.c:1517
static void initialize_image(intro_img_t *img)
Initialize an intro_img_t to default values.
Definition intro.c:140
static intro_cmd_t * intro_cmds
Definition intro.c:57
intro_opcode_t
The possible display operations.
Definition intro.c:42
@ INTRO_TEXT
Definition intro.c:43
@ INTRO_FADEIN
Definition intro.c:44
@ INTRO_FADEOUT
Definition intro.c:45
static int intro_draw_text(char **const sb_list, int sb_size, int sb_index, double offset, double line_height)
Draw intro text onto the screen.
Definition intro.c:274
static int intro_event_handler(int *stop, double *offset, double *vel)
Handle user events (mouse clicks, key presses, etc.).
Definition intro.c:210
#define SIDE_MARGIN
Definition intro.c:30
static int intro_load(const char *text)
Loads the intro stuff.
Definition intro.c:76
#define IMAGE_WIDTH
Definition intro.c:31
static void load_image(intro_img_t *img, const char *img_file)
Initialize an intro_img_t to default values.
Definition intro.c:156
static void intro_cleanup(void)
Cleans up the intro stuff.
Definition intro.c:125
int intro_display(const char *text, const char *mus)
Displays the introduction sequence.
Definition intro.c:306
static char * intro_buf
Definition intro.c:58
static void intro_fade_image_in(intro_img_t *side, intro_img_t *transition, const char *img_file)
Fade an image in.
Definition intro.c:174
static glFont intro_font
Definition intro.c:59
Handles the important game menus.
int music_choose(const char *situation)
Actually runs the music stuff, based on situation.
Definition music.c:412
int music_stop(int disable)
Stops the loaded music.
Definition music.c:260
void music_update(double dt)
Updates the music.
Definition music.c:70
void naev_quit(void)
Flags naev to quit.
Definition naev.c:150
void naev_resize(void)
Wrapper for gl_resize that handles non-GL reinitialization.
Definition naev.c:790
int naev_isQuit(void)
Get if Naev is trying to quit.
Definition naev.c:158
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:40
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition ndata.c:154
char * strndup(const char *s, size_t n)
Return a pointer to a new string, which is a duplicate of the string s (or, if necessary,...
Definition nstring.c:67
glInfo gl_screen
Definition opengl.c:51
void gl_renderScale(const glTexture *texture, double bx, double by, double bw, double bh, const glColour *c)
Blits a texture scaling it.
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:675
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:862
static const double c[]
Definition rng.c:264
int font_size_intro
Definition conf.h:140
Represents a font in memory.
Definition font.h:16
int h
Definition font.h:18
SDL_Window * window
Definition opengl.h:68
The state of a line iteration. This matches the process of rendering text into an on-screen box: An e...
Definition font.h:40
const char * text
Definition font.h:41
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36
A display command (operation code and operand if applicable).
Definition intro.c:49
Intro Image: to be displayed to the side of the scrolling.
Definition intro.c:34
void toolkit_clearKey(void)
Clears the registered keys.
Definition toolkit.c:2036