naev 0.12.6
ship.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "SDL_timer.h"
11#include "physfs.h"
12
13#include "naev.h"
15
16#include "ship.h"
17
18#include "array.h"
19#include "colour.h"
20#include "conf.h"
21#include "faction.h"
22#include "log.h"
23#include "ndata.h"
24#include "nlua.h"
25#include "nlua_camera.h"
26#include "nlua_gfx.h"
27#include "nlua_ship.h"
28#include "nstring.h"
29#include "nxml.h"
30#include "opengl_tex.h"
31#include "shipstats.h"
32#include "slots.h"
33#include "sound.h"
34#include "threadpool.h"
35
36#define XML_SHIP "ship"
37
38#define SHIP_ENGINE "_engine"
39#define SHIP_TARGET "_target"
40#define SHIP_COMM "_comm"
41
42#define VIEW_WIDTH 300
43#define VIEW_HEIGHT 300
44
45#define BUTTON_WIDTH 80
46#define BUTTON_HEIGHT 30
47
48#define STATS_DESC_MAX 512
49
53typedef struct ShipThreadData_ {
54 char *filename;
56 int ret;
58
59static Ship *ship_stack = NULL;
60
61#define SHIP_FBO 3
62static double max_size = 512.; /* Use at least 512 x 512. */
63static double ship_fbos = 0.;
64static GLuint ship_fbo[SHIP_FBO] = { GL_INVALID_ENUM };
65static GLuint ship_tex[SHIP_FBO] = { GL_INVALID_ENUM };
66static GLuint ship_texd[SHIP_FBO] = { GL_INVALID_ENUM };
67static const double ship_aa_scale_base = 2.;
68static double ship_aa_scale = -1.;
69
70/*
71 * Prototypes
72 */
73static int ship_loadPLG( Ship *temp, const char *buf );
74static int ship_parse( Ship *temp, const char *filename, int firstpass );
75static int ship_parseThread( void *ptr );
76static void ship_freeSlot( ShipOutfitSlot *s );
77static void ship_renderFramebuffer3D( const Ship *s, GLuint fbo, double size,
78 double fw, double fh, double engine_glow,
79 double t, const glColour *c,
80 const Lighting *L, const mat4 *H,
81 int blit, unsigned int flags );
82
86static int ship_cmp( const void *p1, const void *p2 )
87{
88 const Ship *s1 = p1;
89 const Ship *s2 = p2;
90 return strcmp( s1->name, s2->name );
91}
92
99const Ship *ship_get( const char *name )
100{
101 const Ship *s = ship_getW( name );
102 if ( s == NULL )
103 WARN( _( "Ship %s does not exist" ), name );
104 return s;
105}
106
113const Ship *ship_getW( const char *name )
114{
115 const Ship s = { .name = (char *)name };
116 return bsearch( &s, ship_stack, array_size( ship_stack ), sizeof( Ship ),
117 ship_cmp );
118}
119
123const char *ship_existsCase( const char *name )
124{
125 for ( int i = 0; i < array_size( ship_stack ); i++ )
126 if ( strcasecmp( name, ship_stack[i].name ) == 0 )
127 return ship_stack[i].name;
128 return NULL;
129}
130
134const Ship *ship_getAll( void )
135{
136 return ship_stack;
137}
138
142int ship_compareTech( const void *arg1, const void *arg2 )
143{
144 const Ship *s1, *s2;
145
146 /* Get ships. */
147 s1 = *(const Ship **)arg1;
148 s2 = *(const Ship **)arg2;
149
150 /* Compare rarity. */
151 if ( s1->rarity < s2->rarity )
152 return +1;
153 else if ( s1->rarity > s2->rarity )
154 return -1;
155
156 /* Compare faction. */
157 if ( s1->faction < s2->faction )
158 return +1;
159 else if ( s1->faction > s2->faction )
160 return -1;
161
162 /* Compare requirements. */
163 /*
164 if ( ( s1->condstr != NULL ) && ( s2->condstr == NULL ) )
165 return -1;
166 else if ( ( s2->condstr != NULL ) && ( s1->condstr == NULL ) )
167 return +1;
168 */
169
170 /* Compare class. */
171 if ( s1->class < s2->class )
172 return +1;
173 else if ( s1->class > s2->class )
174 return -1;
175
176 /* Compare price. */
177 if ( s1->price < s2->price )
178 return +1;
179 else if ( s1->price > s2->price )
180 return -1;
181
182 /* Same. */
183 return strcmp( s1->name, s2->name );
184}
185
192const char *ship_class( const Ship *s )
193{
194 return ship_classToString( s->class );
195}
196
203const char *ship_classDisplay( const Ship *s )
204{
205 if ( s->class_display )
206 return s->class_display;
207 return ship_class( s );
208}
209
216const char *ship_classToString( ShipClass class )
217{
218 switch ( class ) {
219 case SHIP_CLASS_NULL:
220 return "NULL";
221 /* Civilian. */
222 case SHIP_CLASS_YACHT:
223 return N_( "Yacht" );
224 case SHIP_CLASS_COURIER:
225 return N_( "Courier" );
226 case SHIP_CLASS_FREIGHTER:
227 return N_( "Freighter" );
228 case SHIP_CLASS_ARMOURED_TRANSPORT:
229 return N_( "Armoured Transport" );
230 case SHIP_CLASS_BULK_FREIGHTER:
231 return N_( "Bulk Freighter" );
232 /* Military. */
233 case SHIP_CLASS_SCOUT:
234 return N_( "Scout" );
235 case SHIP_CLASS_INTERCEPTOR:
236 return N_( "Interceptor" );
237 case SHIP_CLASS_FIGHTER:
238 return N_( "Fighter" );
239 case SHIP_CLASS_BOMBER:
240 return N_( "Bomber" );
241 case SHIP_CLASS_CORVETTE:
242 return N_( "Corvette" );
243 case SHIP_CLASS_DESTROYER:
244 return N_( "Destroyer" );
245 case SHIP_CLASS_CRUISER:
246 return N_( "Cruiser" );
247 case SHIP_CLASS_BATTLESHIP:
248 return N_( "Battleship" );
249 case SHIP_CLASS_CARRIER:
250 return N_( "Carrier" );
251 /* Unknown. */
252 default:
253 return N_( "Unknown" );
254 }
255}
256
257#define STRTOSHIP( x, y ) \
258 if ( strcmp( str, x ) == 0 ) \
259 return y
265ShipClass ship_classFromString( const char *str )
266{
267 if ( str == NULL )
268 return SHIP_CLASS_NULL;
269 /* Civilian */
270 STRTOSHIP( "Yacht", SHIP_CLASS_YACHT );
271 STRTOSHIP( "Courier", SHIP_CLASS_COURIER );
272 STRTOSHIP( "Freighter", SHIP_CLASS_FREIGHTER );
273 STRTOSHIP( "Armoured Transport", SHIP_CLASS_ARMOURED_TRANSPORT );
274 STRTOSHIP( "Bulk Freighter", SHIP_CLASS_BULK_FREIGHTER );
275
276 /* Military */
277 STRTOSHIP( "Scout", SHIP_CLASS_SCOUT );
278 STRTOSHIP( "Interceptor", SHIP_CLASS_INTERCEPTOR );
279 STRTOSHIP( "Fighter", SHIP_CLASS_FIGHTER );
280 STRTOSHIP( "Bomber", SHIP_CLASS_BOMBER );
281 STRTOSHIP( "Corvette", SHIP_CLASS_CORVETTE );
282 STRTOSHIP( "Destroyer", SHIP_CLASS_DESTROYER );
283 STRTOSHIP( "Cruiser", SHIP_CLASS_CRUISER );
284 STRTOSHIP( "Battleship", SHIP_CLASS_BATTLESHIP );
285 STRTOSHIP( "Carrier", SHIP_CLASS_CARRIER );
286
287 /* Unknown */
288 return SHIP_CLASS_NULL;
289}
290#undef STRTOSHIP
291
295credits_t ship_basePrice( const Ship *s )
296{
297 return s->price;
298}
299
303credits_t ship_buyPrice( const Ship *s )
304{
305 /* Get base price. */
306 credits_t price = ship_basePrice( s );
307
308 for ( int i = 0; i < array_size( s->outfit_structure ); i++ ) {
309 const Outfit *o = s->outfit_structure[i].data;
310 if ( o != NULL )
311 price += o->price;
312 }
313 for ( int i = 0; i < array_size( s->outfit_utility ); i++ ) {
314 const Outfit *o = s->outfit_utility[i].data;
315 if ( o != NULL )
316 price += o->price;
317 }
318 for ( int i = 0; i < array_size( s->outfit_weapon ); i++ ) {
319 const Outfit *o = s->outfit_weapon[i].data;
320 if ( o != NULL )
321 price += o->price;
322 }
323
324 return price;
325}
326
327void ship_renderGfxStore( GLuint fbo, const Ship *s, int size, double dir,
328 double updown, double glow )
329{
330 glBindFramebuffer( GL_FRAMEBUFFER, fbo );
331 glClear( GL_COLOR_BUFFER_BIT );
332
333 /* Give faction colour background if applicable. */
334 if ( s->faction >= 0 ) {
335 const glColour *c = faction_colour( s->faction );
336 if ( c != NULL ) {
337 glUseProgram( shaders.shop_bg.program );
338 gl_renderShader( 0., 0., size, size, 0., &shaders.shop_bg, c, 0 );
339 }
340 }
341
342 if ( s->gfx_3d != NULL ) {
343 Lighting L = L_store_const;
344 mat4 H;
345 double t = SDL_GetTicks() / 1000.;
346
347 /* We rotate the model so it's staring at the player and facing slightly
348 * down. */
349 H = mat4_identity();
350 mat4_rotate( &H, -M_PI_4 + dir, 0.0, 1.0, 0.0 );
351 mat4_rotate( &H, -M_PI_4 * 0.25 + updown, 1.0, 0.0, 0.0 );
352
353 /* Render the model. */
354 ship_renderFramebuffer3D( s, fbo, size, gl_screen.nw, gl_screen.nh, glow,
355 t, &cWhite, &L, &H, 0, OPENGL_TEX_VFLIP );
356 /* Already restore current framebuffer. */
357 } else if ( s->gfx_comm != NULL ) {
358 glTexture *glcomm;
359 double scale, w, h, tx, ty;
360 int sx, sy;
361
362 glcomm = gl_newImage( s->gfx_comm, 0 );
363 glcomm->flags &= ~OPENGL_TEX_VFLIP;
364
365 scale = MIN( size / glcomm->w, size / glcomm->h );
366 w = scale * glcomm->w;
367 h = scale * glcomm->h;
368 gl_getSpriteFromDir( &sx, &sy, s->sx, s->sy, dir );
369 tx = glcomm->sw * (double)( sx ) / glcomm->w;
370 ty = glcomm->sh * ( glcomm->sy - (double)sy - 1 ) / glcomm->h;
371 gl_renderTexture( glcomm, ( size - w ) * 0.5, ( size - h ) * 0.5, w, h,
372 tx, ty, glcomm->srw, glcomm->srh, NULL, 0. );
373
374 gl_freeTexture( glcomm );
375
376 glBindFramebuffer( GL_FRAMEBUFFER, gl_screen.current_fbo );
377 }
378}
379
383glTexture *ship_gfxStore( const Ship *s, int size, double dir, double updown,
384 double glow )
385{
386 double fbosize;
387 GLuint fbo, tex;
388 char buf[STRMAX_SHORT];
389 glTexture *gltex;
390
391 /* Load graphic if applicable. */
392 ship_gfxLoad( (Ship *)s );
393
394 fbosize = size / gl_screen.scale;
395
396 gl_contextSet();
397 gl_fboCreate( &fbo, &tex, fbosize, fbosize );
398
399 ship_renderGfxStore( fbo, s, size, dir, updown, glow );
400
401 glDeleteFramebuffers( 1, &fbo ); /* No need for FBO. */
402 glBindFramebuffer( GL_FRAMEBUFFER, gl_screen.current_fbo );
403 gl_checkErr();
404 gl_contextUnset();
405
406 snprintf( buf, sizeof( buf ), "%s_fbo_gfx_store_%d", s->name, size );
407 gltex = gl_rawTexture( buf, tex, fbosize, fbosize );
408 gltex->flags |= OPENGL_TEX_VFLIP;
409
410 return gltex;
411}
412
418glTexture *ship_gfxComm( const Ship *s, int size, double tilt, double dir,
419 const Lighting *Lscene )
420{
421 double fbosize;
422 GLuint fbo, tex, depth_tex;
423 char buf[STRMAX_SHORT];
424 glTexture *gltex;
425
426 fbosize = ceil( size / gl_screen.scale );
427
428 /* Load graphic if applicable. */
429 ship_gfxLoad( (Ship *)s );
430
431 gl_contextSet();
432 gl_fboCreate( &fbo, &tex, fbosize, fbosize );
433 gl_fboAddDepth( fbo, &depth_tex, fbosize, fbosize );
434 glBindFramebuffer( GL_FRAMEBUFFER, fbo );
435 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
436
437 if ( s->gfx_3d != NULL ) {
438 Lighting L = ( Lscene == NULL ) ? L_default : *Lscene;
439 mat4 H, Hlight;
440 double t = SDL_GetTicks() / 1000.;
441 double rendersize =
442 MIN( MIN( ceil( ship_aa_scale_base * fbosize ), gl_screen.rw ),
443 gl_screen.rh );
444 snprintf( buf, sizeof( buf ), "%s_fbo_gfx_comm_%d", s->name, size );
445
446 /* We rotate the model so it's staring at the player and facing slightly
447 * down. */
448 H = mat4_identity();
449 mat4_rotate( &H, -M_PI_4, 0.0, 1.0, 0.0 );
450 mat4_rotate( &H, -M_PI_4 * 0.25, 1.0, 0.0, 0.0 );
451
452 /* Transform the light so it's consistent with the 3D model. */
453 Hlight = mat4_identity();
454 if ( fabs( tilt ) > DOUBLE_TOL ) {
455 mat4_rotate( &Hlight, M_PI_2, 0.0, 1.0, 0.0 );
456 mat4_rotate( &Hlight, -tilt, 1.0, 0.0, 0.0 );
457 mat4_rotate( &Hlight, dir, 0.0, 1.0, 0.0 );
458 } else
459 mat4_rotate( &Hlight, dir + M_PI_2, 0.0, 1.0, 0.0 );
460 gltf_lightTransform( &L, &Hlight );
461
462 /* Increase ambient a wee bit. */
463 L.ambient_r += 0.1;
464 L.ambient_g += 0.1;
465 L.ambient_b += 0.1;
466 L.intensity *= 1.5;
467
468 /* Render the model. */
469 glBindFramebuffer( GL_FRAMEBUFFER, gl_screen.fbo[2] );
470 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
471 gltf_renderScene( gl_screen.fbo[2], s->gfx_3d, s->gfx_3d->scene_body, &H,
472 t, rendersize, &L );
473 glBindFramebuffer( GL_READ_FRAMEBUFFER, gl_screen.fbo[2] );
474 glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fbo );
475 glBlitFramebuffer( 0, 0, rendersize, rendersize, 0, fbosize, fbosize, 0,
476 GL_COLOR_BUFFER_BIT, GL_LINEAR );
477 } else if ( s->gfx_comm != NULL ) {
478 glTexture *glcomm;
479 double scale, w, h;
480
481 snprintf( buf, sizeof( buf ), "%s_fbo_gfx_comm_%d", s->gfx_comm, size );
482 glcomm = gl_newImage( s->gfx_comm, 0 );
483 glcomm->flags &= ~OPENGL_TEX_VFLIP;
484
485 scale = MIN( size / glcomm->w, size / glcomm->h );
486 w = scale * glcomm->w;
487 h = scale * glcomm->h;
488 gl_renderTexture( glcomm, ( size - w ) * 0.5, ( size - h ) * 0.5, w, h,
489 0., 0., 1., 1., NULL, 0. );
490
491 gl_freeTexture( glcomm );
492 } else
493 WARN( _( "Unable to render comm graphic for ship '%s'!" ), s->name );
494
495 glDeleteFramebuffers( 1, &fbo ); /* No need for FBO. */
496 glDeleteTextures( 1, &depth_tex );
497 glBindFramebuffer( GL_FRAMEBUFFER, gl_screen.current_fbo );
498 gl_checkErr();
499 gl_contextUnset();
500
501 gltex = gl_rawTexture( buf, tex, fbosize, fbosize );
502 gltex->flags |= OPENGL_TEX_VFLIP;
503
504 return gltex;
505}
506
513int ship_gfxAnimated( const Ship *s )
514{
515 if ( s->gfx_3d == NULL )
516 return 0;
517 return ( s->gfx_3d->nanimations > 0 );
518}
519
526int ship_size( const Ship *s )
527{
528 switch ( s->class ) {
529 case SHIP_CLASS_YACHT:
530 case SHIP_CLASS_SCOUT:
531 case SHIP_CLASS_INTERCEPTOR:
532 return 1;
533
534 case SHIP_CLASS_COURIER:
535 case SHIP_CLASS_FIGHTER:
536 case SHIP_CLASS_BOMBER:
537 return 2;
538
539 case SHIP_CLASS_FREIGHTER:
540 case SHIP_CLASS_CORVETTE:
541 return 3;
542
543 case SHIP_CLASS_DESTROYER:
544 case SHIP_CLASS_ARMOURED_TRANSPORT:
545 return 4;
546
547 case SHIP_CLASS_BULK_FREIGHTER:
548 case SHIP_CLASS_CRUISER:
549 return 5;
550
551 case SHIP_CLASS_BATTLESHIP:
552 case SHIP_CLASS_CARRIER:
553 return 6;
554
555 default:
556 return -1;
557 }
558}
559
568static int ship_loadSpaceImage( Ship *temp, const char *str, int sx, int sy )
569{
570 unsigned int flags = OPENGL_TEX_MIPMAPS | OPENGL_TEX_VFLIP;
571 /* If no collision polygon, we use transparency mapping. */
572 if ( array_size( temp->polygon.views ) <= 0 )
573 flags |= OPENGL_TEX_MAPTRANS;
574 temp->gfx_space = gl_newSprite( str, sx, sy, flags );
575 return 0;
576}
577
586static int ship_loadEngineImage( Ship *temp, const char *str, int sx, int sy )
587{
588 temp->gfx_engine = gl_newSprite( str, sx, sy, OPENGL_TEX_MIPMAPS );
589 return ( temp->gfx_engine != NULL );
590}
591
595int ship_gfxLoaded( const Ship *s )
596{
597 return ( ( s->gfx_3d != NULL ) || ( s->gfx_space != NULL ) );
598}
599
604{
605 ThreadQueue *tq = vpool_create();
606 SDL_GL_MakeCurrent( gl_screen.window, NULL );
607
608 for ( int i = 0; i < array_size( ship_stack ); i++ ) {
609 Ship *s = &ship_stack[i];
610 if ( !ship_isFlag( s, SHIP_NEEDSGFX ) )
611 continue;
612 vpool_enqueue( tq, (int ( * )( void * ))ship_gfxLoad, s );
613 ship_rmFlag( s, SHIP_NEEDSGFX );
614 }
615
616 vpool_wait( tq );
617 vpool_cleanup( tq );
618
619 SDL_GL_MakeCurrent( gl_screen.window, gl_screen.context );
620 return 0;
621}
622
629{
630 char str[PATH_MAX], *base;
631 const char *delim, *base_path;
632 const char *ext = ".webp";
633 const char *buf = s->gfx_path;
634 int sx = s->sx;
635 int sy = s->sy;
636 int engine = !s->noengine;
637
638 /* If already loaded, just ignore. */
639 if ( ship_gfxLoaded( s ) )
640 return 0;
641
642 /* Get base path. */
643 delim = strchr( buf, '_' );
644 base = delim == NULL ? strdup( buf ) : strndup( buf, delim - buf );
645 base_path = ( s->base_path != NULL ) ? s->base_path : s->base_type;
646
647 /* Load the 3d model */
648 snprintf( str, sizeof( str ), SHIP_3DGFX_PATH "%s/%s.gltf", base_path, buf );
649 if ( PHYSFS_exists( str ) ) {
650 // DEBUG( "Found 3D graphics for '%s' at '%s'!", s->name, str );
651 s->gfx_3d = gltf_loadFromFile( str );
652
653 /* Replace trails if applicable. */
654 if ( array_size( s->gfx_3d->trails ) > 0 ) {
657 ship_setFlag( s, SHIP_3DTRAILS );
658
659 for ( int i = 0; i < array_size( s->gfx_3d->trails ); i++ ) {
660 GltfTrail *t = &s->gfx_3d->trails[i];
661 ShipTrailEmitter trail;
662
663 /* New trail. */
664 trail.pos = t->pos;
665 vec3_scale( &trail.pos, s->size * 0.5 ); /* Convert to "pixels" */
666 trail.trail_spec = trailSpec_get( t->generator );
667 trail.flags = 0;
668
669 if ( trail.trail_spec != NULL )
670 array_push_back( &s->trail_emitters, trail );
671 }
672 }
673
674 /* Replace mount points if applicable. */
675 if ( array_size( s->gfx_3d->mounts ) > 0 ) {
676 int n = array_size( s->gfx_3d->mounts );
677
678 ship_setFlag( s, SHIP_3DMOUNTS );
679 if ( n < array_size( s->outfit_weapon ) )
680 WARN( _( "Number of 3D weapon mounts from GLTF file for ship '%s' "
681 "is less than the "
682 "number of ship weapons! Got %d, expected at least %d." ),
683 s->name, n, array_size( s->outfit_weapon ) );
684
685 for ( int i = 0; i < array_size( s->outfit_weapon ); i++ ) {
686 ShipMount *sm = &s->outfit_weapon[i].mount;
687 vec3_copy( &sm->pos,
688 &s->gfx_3d->mounts[i % n].pos ); /* Loop over. */
689 vec3_scale( &sm->pos, s->size * 0.5 ); /* Convert to "pixels" */
690 }
691 }
692 }
693
694 /* Determine extension path. */
695 if ( buf[0] == '/' ) /* absolute path. */
696 snprintf( str, sizeof( str ), "%s", buf );
697 else {
698 snprintf( str, sizeof( str ), SHIP_GFX_PATH "%s/%s%s", base, buf, ext );
699 if ( !PHYSFS_exists( str ) ) {
700 ext = ".png";
701 snprintf( str, sizeof( str ), SHIP_GFX_PATH "%s/%s%s", base, buf,
702 ext );
703 }
704 }
705
706 /* Load the polygon. */
707 ship_loadPLG( s,
708 ( s->polygon_path != NULL ) ? s->polygon_path : s->gfx_path );
709
710 /* If we have 3D and polygons, we'll ignore the 2D stuff. */
711 if ( ( s->gfx_3d != NULL ) && ( array_size( s->polygon.views ) > 0 ) ) {
712 free( base );
713 return 0;
714 }
715
716 /* Get the comm graphic for future loading. */
717 if ( s->gfx_comm == NULL )
718 SDL_asprintf( &s->gfx_comm, SHIP_GFX_PATH "%s/%s" SHIP_COMM "%s", base,
719 buf, ext );
720
721 /* Load the space sprite. */
722 ship_loadSpaceImage( s, str, sx, sy );
723
724 /* Load the engine sprite .*/
725 if ( engine ) {
726 snprintf( str, sizeof( str ), SHIP_GFX_PATH "%s/%s" SHIP_ENGINE "%s",
727 base, buf, ext );
728 ship_loadEngineImage( s, str, sx, sy );
729 if ( s->gfx_engine == NULL )
730 WARN( _( "Ship '%s' does not have an engine sprite (%s)." ), s->name,
731 str );
732 }
733 free( base );
734
735#if 0
736#if DEBUGGING
737 if ( ( s->gfx_space != NULL ) &&
738 ( round( s->size ) != round( s->gfx_space->sw ) ) )
739 WARN( ( "Mismatch between 'size' and 'gfx_space' sprite size for ship "
740 "'%s'! 'size' should be %.0f!" ),
741 s->name, s->gfx_space->sw );
742#endif /* DEBUGGING */
743#endif
744
745 return 0;
746}
747
754static int ship_loadPLG( Ship *temp, const char *buf )
755{
756 char file[PATH_MAX];
757 xmlDocPtr doc;
758 xmlNodePtr node;
759
760 if ( temp->gfx_3d != NULL )
761 snprintf( file, sizeof( file ), "%s%s.xml", SHIP_POLYGON_PATH3D, buf );
762 else
763 snprintf( file, sizeof( file ), "%s%s.xml", SHIP_POLYGON_PATH, buf );
764
765 /* See if the file does exist. */
766 if ( !PHYSFS_exists( file ) ) {
767 WARN( _( "%s xml collision polygon does not exist! Please use the "
768 "script '%s' found in Naev's main repository." ),
769 file, "utils/polygonize.py" );
770 return 0;
771 }
772
773 /* Load the XML. */
774 doc = xml_parsePhysFS( file );
775 if ( doc == NULL )
776 return 0;
777
778 node = doc->xmlChildrenNode; /* First polygon node */
779 if ( node == NULL ) {
780 xmlFreeDoc( doc );
781 WARN( _( "Malformed %s file: does not contain elements" ), file );
782 return 0;
783 }
784
785 do { /* load the polygon data */
786 if ( xml_isNode( node, "polygons" ) )
787 poly_load( &temp->polygon, node, file );
788 } while ( xml_nextNode( node ) );
789
790 xmlFreeDoc( doc );
791 return 0;
792}
793
803static int ship_parseSlot( Ship *temp, ShipOutfitSlot *slot,
804 OutfitSlotType type, xmlNodePtr node )
805{
806 OutfitSlotSize base_size;
807 char *buf;
808
809 /* Initialize. */
810 memset( slot, 0, sizeof( ShipOutfitSlot ) );
811 /* Parse size. */
812 xmlr_attr_strd( node, "size", buf );
813 if ( buf != NULL )
814 base_size = outfit_toSlotSize( buf );
815 else {
816 WARN( _( "Ship '%s' has undefined slot size, setting to '%s'" ),
817 temp->name, "Small" );
818 base_size = OUTFIT_SLOT_SIZE_LIGHT;
819 }
820 free( buf );
821
822 /* Get mount point for weapons. */
823 if ( type == OUTFIT_SLOT_WEAPON ) {
824 xmlr_attr_float( node, "x", slot->mount.pos.v[0] );
825 xmlr_attr_float( node, "y", slot->mount.pos.v[1] );
826 /* Since we measure in pixels, we have to modify it so it
827 * doesn't get corrected by the ortho correction. */
828 slot->mount.pos.v[1] *= M_SQRT2;
829 xmlr_attr_float( node, "h", slot->mount.pos.v[2] );
830 }
831
832 /* Parse property. */
833 xmlr_attr_strd( node, "prop", buf );
834 if ( buf != NULL ) {
835 slot->slot.spid = sp_get( buf );
836 slot->exclusive = sp_exclusive( slot->slot.spid );
837 slot->required = sp_required( slot->slot.spid );
838 slot->visible = sp_visible( slot->slot.spid );
839 slot->locked = sp_locked( slot->slot.spid );
840 free( buf );
841 }
842 // TODO: consider inserting those two parse blocks below inside the parse
843 // block above
844
845 /* Parse exclusive flag, default false. */
846 xmlr_attr_int_def( node, "exclusive", slot->exclusive, slot->exclusive );
847 /* TODO: decide if exclusive should even belong in ShipOutfitSlot,
848 * remove this hack, and fix slot->exclusive to slot->slot.exclusive
849 * in its two previous occurrences, meaning three lines above and 12
850 * lines above */
851 /* hack */
852 slot->slot.exclusive = slot->exclusive;
853
854 /* Parse required flag, default false. */
855 xmlr_attr_int_def( node, "required", slot->required, slot->required );
856
857 /* Parse locked flag, default false. */
858 xmlr_attr_int_def( node, "locked", slot->locked, slot->locked );
859
860 /* Name if applicable. */
861 xmlr_attr_strd( node, "name", slot->name );
862
863 /* Parse default outfit. */
864 buf = xml_get( node );
865 if ( buf != NULL ) {
866 const Outfit *o = outfit_get( buf );
867 if ( o == NULL )
868 WARN( _( "Ship '%s' has default outfit '%s' which does not exist." ),
869 temp->name, buf );
870 slot->data = o;
871 }
872
873 /* Set stuff. */
874 slot->slot.size = base_size;
875 slot->slot.type = type;
876
877 /* Required slots need a default outfit. */
878 if ( slot->required && ( slot->data == NULL ) )
879 WARN( _( "Ship '%s' has required slot without a default outfit." ),
880 temp->name );
881
882 return 0;
883}
884
893static int ship_parse( Ship *temp, const char *filename, int firstpass )
894{
895 xmlNodePtr parent, node;
896 xmlDocPtr doc;
897 ShipTrailEmitter trail;
898
899 /* On second pass we ignore inheriting ones. */
900 if ( ( !firstpass ) && ( temp->inherits == NULL ) )
901 return 0;
902
903 if ( firstpass ) {
904 /* Load the XML. */
905 doc = xml_parsePhysFS( filename );
906 if ( doc == NULL )
907 return -1;
908
909 parent = doc->xmlChildrenNode; /* First ship node */
910 if ( parent == NULL ) {
911 xmlFreeDoc( doc );
912 WARN( _( "Malformed %s file: does not contain elements" ), filename );
913 return -1;
914 }
915
916 /* Clear memory. */
917 memset( temp, 0, sizeof( Ship ) );
918
919 /* Defaults. */
920 ss_statsInit( &temp->stats_array );
921 temp->dt_default = 1.;
922 temp->faction = -1;
924
925 /* Lua defaults. */
926 temp->lua_env = LUA_NOREF;
927 temp->lua_descextra = LUA_NOREF;
928 temp->lua_init = LUA_NOREF;
929 temp->lua_cleanup = LUA_NOREF;
930 temp->lua_update = LUA_NOREF;
931 temp->lua_dt = 0.1;
932 temp->lua_explode_init = LUA_NOREF;
933 temp->lua_explode_update = LUA_NOREF;
934
935 /* Get name. */
936 xmlr_attr_strd_free( parent, "name", temp->name );
937 if ( temp->name == NULL )
938 WARN( _( "Ship in %s has invalid or no name" ), SHIP_DATA_PATH );
939
940 /* Get inheritance. */
941 xmlr_attr_strd_free( parent, "inherits", temp->inherits );
942 if ( temp->inherits != NULL ) {
943 /* Don't free doc as it gets reused next iteration. */
944 temp->rawdata = doc;
945 return 0;
946 }
947 } else {
948 doc = temp->rawdata;
949 parent = doc->xmlChildrenNode; /* First ship node */
950#define STRDUP_( x ) ( ( x == NULL ) ? NULL : strdup( x ) )
951#define ARRAYDUP_( x, y ) \
952 do { \
953 for ( int i = 0; i < array_size( y ); i++ ) \
954 array_push_back( &x, y[i] ); \
955 } while ( 0 )
956 Ship t = *temp;
957 Ship *base = (Ship *)ship_get( temp->inherits );
958 *temp = *base;
959 temp->rawdata = doc;
960 temp->inherits = t.inherits;
961 temp->name = t.name;
962 temp->base_type = STRDUP_( base->base_type );
963 temp->base_path = STRDUP_( base->base_path );
964 temp->class_display = STRDUP_( base->class_display );
965 temp->license = STRDUP_( base->license );
966 temp->cond = STRDUP_( base->cond );
967 temp->condstr = STRDUP_( base->condstr );
968 temp->fabricator = STRDUP_( base->fabricator );
969 temp->description = STRDUP_( base->description );
970 temp->desc_extra = STRDUP_( base->desc_extra );
971 temp->gfx_path = STRDUP_( base->gfx_path );
972 temp->polygon_path = STRDUP_( base->polygon_path );
973 temp->gfx_comm = STRDUP_( base->gfx_comm );
974 if ( base->gfx_overlays != NULL ) {
976 for ( int i = 0; i < array_size( base->gfx_overlays ); i++ )
978 gl_dupTexture( base->gfx_overlays[i] ) );
979 }
982 ARRAYDUP_( temp->outfit_structure, base->outfit_structure );
984 ARRAYDUP_( temp->outfit_utility, base->outfit_utility );
986 ARRAYDUP_( temp->outfit_weapon, base->outfit_weapon );
987 temp->desc_stats = STRDUP_( base->desc_stats );
988 temp->stats = NULL;
989 ShipStatList *ll = base->stats;
990 while ( ll != NULL ) {
991 ShipStatList *ln = calloc( 1, sizeof( ShipStatList ) );
992 *ln = *ll;
993 ln->next = temp->stats;
994 temp->stats = ln;
995 ll = ll->next;
996 }
997 temp->tags = array_create( char * );
998 for ( int i = 0; i < array_size( base->tags ); i++ )
999 array_push_back( &temp->tags, strdup( base->tags[i] ) );
1000 temp->lua_file = STRDUP_( base->lua_file );
1001#undef STRDUP_
1002
1003 /* Have to correct some post-processing. */
1004 temp->dmg_absorb *= 100.;
1005 temp->turn *= 180. / M_PI;
1006 }
1007
1008 /* Load the rest of the data. */
1009 node = parent->xmlChildrenNode;
1010 do { /* load all the data */
1011
1012 /* Only handle nodes. */
1013 xml_onlyNodes( node );
1014
1015 if ( xml_isNode( node, "class" ) ) {
1016 xmlr_attr_strd_free( node, "display", temp->class_display );
1017 temp->class = ship_classFromString( xml_get( node ) );
1018 continue;
1019 }
1020 if ( xml_isNode( node, "gfx" ) || xml_isNode( node, "GFX" ) ) {
1021 const char *str = xml_get( node );
1022 /* TODO remove for 0.13.0 */
1023 if ( xml_isNode( node, "GFX" ) )
1024 WARN( _( "Ship '%s': using <GFX> instead of <gfx>!" ), temp->name );
1025
1026 /* Get base graphic name. */
1027 if ( str == NULL ) {
1028 WARN( _( "Ship '%s' has NULL tag '%s'!" ), temp->name, "gfx" );
1029 continue;
1030 } else {
1031 free( temp->gfx_path );
1032 temp->gfx_path = strdup( str );
1033 }
1034
1035 /* Parse attributes. */
1036 xmlr_attr_float_def( node, "size", temp->size, 1 );
1037 xmlr_attr_int_def( node, "sx", temp->sx, 8 );
1038 xmlr_attr_int_def( node, "sy", temp->sy, 8 );
1039 xmlr_attr_strd_free( node, "comm", temp->gfx_comm );
1040 xmlr_attr_int( node, "noengine", temp->noengine );
1041 xmlr_attr_strd_free( node, "polygon", temp->polygon_path );
1042
1043 /* Graphics are now lazy loaded. */
1044
1045 continue;
1046 }
1047
1048 if ( xml_isNode( node, "faction" ) ) {
1049 temp->faction = faction_get( xml_get( node ) );
1050 continue;
1051 }
1052
1053 if ( xml_isNode( node, "gfx_overlays" ) ) {
1054 xmlNodePtr cur = node->children;
1055 array_free( temp->gfx_overlays );
1057 do {
1058 xml_onlyNodes( cur );
1059 if ( xml_isNode( cur, "gfx_overlay" ) )
1061 xml_parseTexture( cur, OVERLAY_GFX_PATH "%s", 1,
1062 1, OPENGL_TEX_MIPMAPS ) );
1063 } while ( xml_nextNode( cur ) );
1064 continue;
1065 }
1066
1067 if ( xml_isNode( node, "sound" ) ) {
1068 xmlr_attr_float_def( node, "pitch", temp->engine_pitch, 1. );
1069 temp->sound = sound_get( xml_get( node ) );
1070 continue;
1071 }
1072 if ( xml_isNode( node, "base_type" ) ) {
1073 const char *nstr = xml_get( node );
1074 xmlr_attr_strd_free( node, "path", temp->base_path );
1075 free( temp->base_type );
1076 temp->base_type = ( nstr != NULL ) ? strdup( nstr ) : NULL;
1077 continue;
1078 }
1079 xmlr_float( node, "time_mod", temp->dt_default );
1080 xmlr_long( node, "price", temp->price );
1081 xmlr_strd_free( node, "license", temp->license );
1082 xmlr_strd_free( node, "cond", temp->cond );
1083 xmlr_strd_free( node, "condstr", temp->condstr );
1084 xmlr_strd_free( node, "fabricator", temp->fabricator );
1085 xmlr_strd_free( node, "description", temp->description );
1086 xmlr_strd_free( node, "desc_extra", temp->desc_extra );
1087 xmlr_int( node, "points", temp->points );
1088 xmlr_int( node, "rarity", temp->rarity );
1089 if ( xml_isNode( node, "lua" ) ) {
1090 const char *nstr = xml_get( node );
1091 if ( nstr == NULL ) {
1092 WARN( _( "Ship '%s' has invalid '%s' node." ), temp->name, "lua" );
1093 continue;
1094 }
1095 free( temp->lua_file );
1096 if ( nstr[0] == '/' )
1097 temp->lua_file = strdup( nstr );
1098 else
1099 SDL_asprintf( &temp->lua_file, SHIP_DATA_LUA_PATH "%s", nstr );
1100 continue;
1101 }
1102
1103 if ( xml_isNode( node, "flags" ) ) {
1104 xmlNodePtr cur = node->children;
1105 do {
1106 xml_onlyNodes( cur );
1107 if ( xml_isNode( cur, "noplayer" ) ) {
1108 ship_setFlag( temp, SHIP_NOPLAYER );
1109 continue;
1110 }
1111 if ( xml_isNode( cur, "noescort" ) ) {
1112 ship_setFlag( temp, SHIP_NOESCORT );
1113 continue;
1114 }
1115 if ( xml_isNode( cur, "unique" ) ) {
1116 ship_setFlag( temp, SHIP_UNIQUE );
1117 continue;
1118 }
1119 // cppcheck-suppress nullPointerRedundantCheck
1120 WARN( _( "Ship '%s' has unknown flags node '%s'." ), temp->name,
1121 cur->name );
1122 } while ( xml_nextNode( cur ) );
1123 continue;
1124 }
1125
1126 if ( xml_isNode( node, "trail_generator" ) ) {
1127 const char *buf;
1128 xmlr_attr_float( node, "x", trail.pos.v[0] );
1129 xmlr_attr_float( node, "y", trail.pos.v[1] );
1130 xmlr_attr_float( node, "h", trail.pos.v[2] );
1131 xmlr_attr_int_def( node, "always_under", trail.flags,
1132 SHIP_TRAIL_ALWAYS_UNDER );
1133 buf = xml_get( node );
1134 if ( buf == NULL )
1135 buf = "default";
1136 trail.trail_spec = trailSpec_get( buf );
1137 if ( trail.trail_spec != NULL )
1138 array_push_back( &temp->trail_emitters, trail );
1139 continue;
1140 }
1141
1142 if ( xml_isNode( node, "movement" ) ) {
1143 xmlNodePtr cur = node->children;
1144 do {
1145 xml_onlyNodes( cur );
1146 xmlr_float( cur, "accel", temp->accel );
1147 xmlr_float( cur, "turn", temp->turn );
1148 xmlr_float( cur, "speed", temp->speed );
1149 /* All the xmlr_ stuff have continue cases. */
1150 // cppcheck-suppress nullPointerRedundantCheck
1151 WARN( _( "Ship '%s' has unknown movement node '%s'." ), temp->name,
1152 cur->name );
1153 } while ( xml_nextNode( cur ) );
1154 continue;
1155 }
1156 if ( xml_isNode( node, "health" ) ) {
1157 xmlNodePtr cur = node->children;
1158 do {
1159 xml_onlyNodes( cur );
1160 xmlr_float( cur, "absorb", temp->dmg_absorb );
1161 xmlr_float( cur, "armour", temp->armour );
1162 xmlr_float( cur, "armour_regen", temp->armour_regen );
1163 xmlr_float( cur, "shield", temp->shield );
1164 xmlr_float( cur, "shield_regen", temp->shield_regen );
1165 xmlr_float( cur, "energy", temp->energy );
1166 xmlr_float( cur, "energy_regen", temp->energy_regen );
1167 /* All the xmlr_ stuff have continue cases. */
1168 // cppcheck-suppress nullPointerRedundantCheck
1169 WARN( _( "Ship '%s' has unknown health node '%s'." ), temp->name,
1170 cur->name );
1171 } while ( xml_nextNode( cur ) );
1172 continue;
1173 }
1174 if ( xml_isNode( node, "characteristics" ) ) {
1175 xmlNodePtr cur = node->children;
1176 do {
1177 xml_onlyNodes( cur );
1178 xmlr_int( cur, "crew", temp->crew );
1179 xmlr_float( cur, "mass", temp->mass );
1180 xmlr_float( cur, "cpu", temp->cpu );
1181 xmlr_int( cur, "fuel", temp->fuel );
1182 xmlr_int( cur, "fuel_consumption", temp->fuel_consumption );
1183 xmlr_float( cur, "cargo", temp->cap_cargo );
1184 /* All the xmlr_ stuff have continue cases. */
1185 // cppcheck-suppress nullPointerRedundantCheck
1186 WARN( _( "Ship '%s' has unknown characteristic node '%s'." ),
1187 temp->name, cur->name );
1188 } while ( xml_nextNode( cur ) );
1189 continue;
1190 }
1191 if ( xml_isNode( node, "slots" ) ) {
1192 /* Clean up, just in case. */
1194 array_free( temp->outfit_utility );
1195 array_free( temp->outfit_weapon );
1196 /* Allocate the space. */
1200
1201 /* Initialize the mounts. */
1202 xmlNodePtr cur = node->children;
1203 do {
1204 xml_onlyNodes( cur );
1205 if ( xml_isNode( cur, "structure" ) )
1206 ship_parseSlot( temp, &array_grow( &temp->outfit_structure ),
1207 OUTFIT_SLOT_STRUCTURE, cur );
1208 else if ( xml_isNode( cur, "utility" ) )
1209 ship_parseSlot( temp, &array_grow( &temp->outfit_utility ),
1210 OUTFIT_SLOT_UTILITY, cur );
1211 else if ( xml_isNode( cur, "weapon" ) )
1212 ship_parseSlot( temp, &array_grow( &temp->outfit_weapon ),
1213 OUTFIT_SLOT_WEAPON, cur );
1214 else if ( xml_isNode( cur, "intrinsic" ) ) {
1215 const Outfit *o = outfit_get( xml_get( cur ) );
1216 if ( o == NULL ) {
1217 WARN( _( "Ship '%s' has unknown intrinsic outfit '%s'" ),
1218 temp->name, xml_get( cur ) );
1219 continue;
1220 }
1221 if ( temp->outfit_intrinsic == NULL )
1222 temp->outfit_intrinsic =
1223 (Outfit const **)array_create( Outfit * );
1224 array_push_back( &temp->outfit_intrinsic, o );
1225 } else
1226 WARN( _( "Ship '%s' has unknown slot node '%s'." ), temp->name,
1227 cur->name );
1228 } while ( xml_nextNode( cur ) );
1230 array_shrink( &temp->outfit_utility );
1231 array_shrink( &temp->outfit_weapon );
1232 continue;
1233 }
1234
1235 /* Parse ship stats. */
1236 if ( xml_isNode( node, "stats" ) ) {
1237 xmlNodePtr cur = node->children;
1238 /* Clear if duplicated. */
1239 if ( temp->stats != NULL ) {
1240 ss_free( temp->stats );
1241 temp->stats = NULL;
1242 }
1243 do {
1244 ShipStatList *ll;
1245 xml_onlyNodes( cur );
1246 ll = ss_listFromXML( cur );
1247 if ( ll != NULL ) {
1248 ll->next = temp->stats;
1249 temp->stats = ll;
1250 continue;
1251 }
1252 WARN( _( "Ship '%s' has unknown stat '%s'." ), temp->name,
1253 cur->name );
1254 } while ( xml_nextNode( cur ) );
1255
1256 /* Load array. */
1257 ss_sort( &temp->stats );
1258 ss_statsInit( &temp->stats_array );
1259 ss_statsMergeFromList( &temp->stats_array, temp->stats );
1260
1261 /* Create description. */
1262 if ( temp->stats != NULL ) {
1263 int i;
1264 free( temp->desc_stats );
1265 temp->desc_stats = malloc( STATS_DESC_MAX );
1267 0 );
1268 if ( i <= 0 ) {
1269 free( temp->desc_stats );
1270 temp->desc_stats = NULL;
1271 }
1272 }
1273
1274 continue;
1275 }
1276
1277 /* Parse tags. */
1278 if ( xml_isNode( node, "tags" ) ) {
1279 xmlNodePtr cur = node->children;
1280 for ( int i = 0; i < array_size( temp->tags ); i++ )
1281 free( temp->tags[i] );
1282 array_free( temp->tags );
1283 temp->tags = array_create( char * );
1284 do {
1285 xml_onlyNodes( cur );
1286 if ( xml_isNode( cur, "tag" ) ) {
1287 const char *tmp = xml_get( cur );
1288 if ( tmp != NULL )
1289 array_push_back( &temp->tags, strdup( tmp ) );
1290 continue;
1291 }
1292 WARN( _( "Ship '%s' has unknown node in tags '%s'." ), temp->name,
1293 cur->name );
1294 } while ( xml_nextNode( cur ) );
1295 continue;
1296 }
1297
1298 /* Used by on-valid and NSH utils, no in-game meaning. */
1299 if ( xml_isNode( node, "mission" ) )
1300 continue;
1301
1302 DEBUG( _( "Ship '%s' has unknown node '%s'." ), temp->name, node->name );
1303 } while ( xml_nextNode( node ) );
1304
1305 /* Post processing. */
1306 temp->dmg_absorb /= 100.;
1307 temp->turn *= M_PI / 180.; /* Convert to rad. */
1308
1309 /* Check license. */
1310 if ( temp->license && !outfit_licenseExists( temp->license ) )
1311 WARN( _( "Ship '%s' has inexistent license requirement '%s'!" ),
1312 temp->name, temp->license );
1313
1314 /* Ship XML validator */
1315#define MELEMENT( o, s ) \
1316 if ( o ) \
1317 WARN( _( "Ship '%s' missing '%s' element" ), temp->name, s )
1318 MELEMENT( temp->name == NULL, "name" );
1319 MELEMENT( temp->base_type == NULL, "base_type" );
1320 MELEMENT( ( temp->gfx_path == NULL ), "GFX" );
1321 MELEMENT( temp->size <= 0., "GFX.size" );
1322 MELEMENT( temp->class == SHIP_CLASS_NULL, "class" );
1323 MELEMENT( temp->points == 0, "points" );
1324 MELEMENT( temp->price == 0, "price" );
1325 MELEMENT( temp->dt_default <= 0., "time_mod" );
1326 MELEMENT( temp->fabricator == NULL, "fabricator" );
1327 MELEMENT( temp->description == NULL, "description" );
1328 MELEMENT( temp->armour == 0., "armour" );
1329 MELEMENT( ( temp->cond != NULL ) && ( temp->condstr == NULL ), "condstr" );
1330 MELEMENT( ( temp->cond == NULL ) && ( temp->condstr != NULL ), "cond" );
1331 /*MELEMENT(temp->accel==0.,"accel");
1332 MELEMENT(temp->turn==0.,"turn");
1333 MELEMENT(temp->speed==0.,"speed");
1334 MELEMENT(temp->shield==0.,"shield");
1335 MELEMENT(temp->shield_regen==0.,"shield_regen");
1336 MELEMENT(temp->energy==0.,"energy");
1337 MELEMENT(temp->energy_regen==0.,"energy_regen");
1338 MELEMENT(temp->fuel==0.,"fuel");*/
1339 MELEMENT( temp->crew == 0, "crew" );
1340 MELEMENT( temp->mass == 0., "mass" );
1341 MELEMENT( temp->fuel_consumption == 0, "fuel_consumption" );
1342 /*MELEMENT(temp->cap_cargo==0,"cargo");
1343 MELEMENT(temp->cpu==0.,"cpu");*/
1344#undef MELEMENT
1345
1346 xmlFreeDoc( doc );
1347
1348 return 0;
1349}
1350
1354static void ship_renderFramebuffer3D( const Ship *s, GLuint fbo, double size,
1355 double fw, double fh, double engine_glow,
1356 double t, const glColour *c,
1357 const Lighting *L, const mat4 *H,
1358 int blit, unsigned int flags )
1359{
1360 double scale = ship_aa_scale * size;
1361 GltfObject *obj = s->gfx_3d;
1362 mat4 projection, tex_mat;
1363 GLint sbuffer = ceil( scale );
1364
1365 glBindFramebuffer( GL_FRAMEBUFFER, ship_fbo[0] );
1366
1367 /* Only clear the necessary area. */
1368 glEnable( GL_SCISSOR_TEST );
1369 glScissor( 0, 0, sbuffer, sbuffer );
1370 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1371 glDisable( GL_SCISSOR_TEST );
1372
1373 /* Compute projection and texture matrices. */
1374 projection = mat4_ortho( 0., fw, 0, fh, -1., 1. );
1375 mat4_scale_xy( &projection, scale * gl_screen.scale,
1376 scale * gl_screen.scale );
1377 tex_mat = mat4_identity();
1378 mat4_scale_xy( &tex_mat, scale / ship_fbos, scale / ship_fbos );
1379
1380 /* Actually render. */
1381 if ( ( engine_glow > 0. ) && ( obj->scene_engine >= 0 ) ) {
1382 if ( engine_glow >= 1. ) {
1383 gltf_renderScene( ship_fbo[0], obj, obj->scene_engine, H, t, scale,
1384 L );
1385 } else {
1386 /* More scissors on the remaining ship fbos. */
1387 glEnable( GL_SCISSOR_TEST );
1388 glBindFramebuffer( GL_FRAMEBUFFER, ship_fbo[2] );
1389 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1390 glBindFramebuffer( GL_FRAMEBUFFER, ship_fbo[1] );
1391 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1392 glDisable( GL_SCISSOR_TEST );
1393
1394 /* First render separately. */
1395 gltf_renderScene( ship_fbo[1], obj, obj->scene_body, H, t, scale, L );
1396 gltf_renderScene( ship_fbo[2], obj, obj->scene_engine, H, t, scale,
1397 L );
1398
1399 /* Now merge to main framebuffer. */
1400 glBindFramebuffer( GL_FRAMEBUFFER, ship_fbo[0] );
1401 gl_renderTextureInterpolateRawH( ship_tex[2], ship_tex[1], engine_glow,
1402 &projection, &tex_mat, &cWhite );
1403
1404 /* Copy depth over. */
1405 GLint blitsize = scale;
1406 glBindFramebuffer( GL_READ_FRAMEBUFFER, ship_fbo[1] );
1407 glBindFramebuffer( GL_DRAW_FRAMEBUFFER, ship_fbo[0] );
1408 glBlitFramebuffer( 0, 0, blitsize, blitsize, 0, 0, blitsize, blitsize,
1409 GL_DEPTH_BUFFER_BIT, GL_NEAREST );
1410
1411 /* TODO fix this area, it causes issues with rendering pilots to the
1412 * framebuffer in the gui. */
1413 }
1414 } else
1415 gltf_renderScene( ship_fbo[0], obj, obj->scene_body, H, t, scale, L );
1416
1417 /*
1418 * First do sharpen pass.
1419 */
1420 glBindFramebuffer( GL_FRAMEBUFFER, ship_fbo[1] );
1421 glEnable( GL_SCISSOR_TEST );
1422 glScissor( 0, 0, sbuffer + ship_aa_scale_base,
1423 sbuffer + ship_aa_scale_base );
1424 glClear( GL_COLOR_BUFFER_BIT );
1425 glDisable( GL_SCISSOR_TEST );
1426
1427 glUseProgram( shaders.texture_sharpen.program );
1428 glBindTexture( GL_TEXTURE_2D, ship_tex[0] );
1429
1430 glEnableVertexAttribArray( shaders.texture_sharpen.vertex );
1431 gl_vboActivateAttribOffset( gl_squareVBO, shaders.texture_sharpen.vertex, 0,
1432 2, GL_FLOAT, 0 );
1433
1434 /* Set shader uniforms. */
1435 gl_uniformColour( shaders.texture_sharpen.colour, c );
1436 gl_uniformMat4( shaders.texture_sharpen.projection, &projection );
1437 gl_uniformMat4( shaders.texture_sharpen.tex_mat, &tex_mat );
1438
1439 /* Draw. */
1440 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
1441
1442 /* Clear state. */
1443 glDisableVertexAttribArray( shaders.texture_sharpen.vertex );
1444
1445 /*
1446 * Now downsample pass.
1447 */
1448 /* Tests show that for 2x AA, linear is visually indifferent from bicubic.
1449 * The padding is to ensure that there is a one pixel buffer of alpha 0.
1450 */
1451 if ( blit ) {
1452 GLint sin = sbuffer + (GLint)ship_aa_scale_base;
1453 GLint sout = ceil( size / gl_screen.scale ) + 1;
1454 glBindFramebuffer( GL_READ_FRAMEBUFFER, ship_fbo[1] );
1455 glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fbo );
1456 if ( flags & OPENGL_TEX_VFLIP ) {
1457 glBlitFramebuffer( 0, 0, sin, sin, 0, sout, sout, 0,
1458 GL_COLOR_BUFFER_BIT, GL_LINEAR );
1459 /* Depth can only use NEAREST filtering. */
1460 glBindFramebuffer( GL_READ_FRAMEBUFFER, ship_fbo[0] );
1461 glBlitFramebuffer( 0, 0, sin, sin, 0, sout, sout, 0,
1462 GL_DEPTH_BUFFER_BIT, GL_NEAREST );
1463 } else {
1464 glBlitFramebuffer( 0, 0, sin, sin, 0, 0, sout, sout,
1465 GL_COLOR_BUFFER_BIT, GL_LINEAR );
1466 glBindFramebuffer( GL_READ_FRAMEBUFFER, ship_fbo[0] );
1467 glBlitFramebuffer( 0, 0, sin, sin, 0, 0, sout, sout,
1468 GL_DEPTH_BUFFER_BIT, GL_NEAREST );
1469 }
1470 } else {
1471 glBindFramebuffer( GL_FRAMEBUFFER, fbo );
1472 tex_mat = mat4_identity();
1473 if ( flags & OPENGL_TEX_VFLIP ) {
1474 tex_mat.m[1][1] = -1.;
1475 tex_mat.m[3][1] = 0.5;
1476 }
1477 gl_renderTextureRawH( ship_tex[1], &projection, &tex_mat, &cWhite );
1478 }
1479
1480 glBindFramebuffer( GL_FRAMEBUFFER, gl_screen.current_fbo );
1481
1482 /* anything failed? */
1483 gl_checkErr();
1484}
1485
1489void ship_renderFramebuffer( const Ship *s, GLuint fbo, double fw, double fh,
1490 double dir, double engine_glow, double tilt,
1491 double r, int sx, int sy, const glColour *c,
1492 const Lighting *L )
1493{
1494 if ( c == NULL )
1495 c = &cWhite;
1496
1497 if ( s->gfx_3d != NULL ) {
1498 double t = elapsed_time_mod + r * 300.;
1499
1500 /* Determine the model transformation. */
1501 mat4 H = mat4_identity();
1502 if ( fabs( tilt ) > DOUBLE_TOL ) {
1503 mat4_rotate( &H, M_PI_2, 0.0, 1.0, 0.0 );
1504 mat4_rotate( &H, -tilt, 1.0, 0.0, 0.0 );
1505 mat4_rotate( &H, dir, 0.0, 1.0, 0.0 );
1506 } else
1507 mat4_rotate( &H, dir + M_PI_2, 0.0, 1.0, 0.0 );
1508
1509 ship_renderFramebuffer3D( s, fbo, s->size, fw, fh, engine_glow, t, c, L,
1510 &H, 1, 0 );
1511 /* Already restore current framebuffer. */
1512 } else {
1513 double tx, ty;
1514 const glTexture *sa, *sb;
1515 mat4 tmpm;
1516
1517 glBindFramebuffer( GL_FRAMEBUFFER, fbo );
1518
1519 sa = s->gfx_space;
1520 sb = s->gfx_engine;
1521
1522 /* Only clear the necessary area. */
1523 glEnable( GL_SCISSOR_TEST );
1524 glScissor( 0, 0, sa->sw / gl_screen.scale + 1,
1525 sa->sh / gl_screen.scale + 1 );
1526 glClear( GL_COLOR_BUFFER_BIT );
1527 glDisable( GL_SCISSOR_TEST );
1528
1529 /* Texture coords */
1530 tx = sa->sw * (double)( sx ) / sa->w;
1531 ty = sa->sh * ( sa->sy - (double)sy - 1 ) / sa->h;
1532
1533 tmpm = gl_view_matrix;
1534 gl_view_matrix = mat4_ortho( 0., fw, 0, fh, -1., 1. );
1535
1536 gl_renderTextureInterpolate( sb, sa, engine_glow, 0., 0., sa->sw, sa->sh,
1537 tx, ty, sa->srw, sa->srh, c );
1538
1539 gl_view_matrix = tmpm;
1540
1541 glBindFramebuffer( GL_FRAMEBUFFER, gl_screen.current_fbo );
1542 }
1543}
1544
1548static int ship_parseThread( void *ptr )
1549{
1550 ShipThreadData *data = ptr;
1551 /* Load the ship. */
1552 data->ret = ship_parse( &data->ship, data->filename, 1 );
1553 /* Render if necessary. */
1555 gl_contextSet();
1557 gl_contextUnset();
1558 }
1559 return data->ret;
1560}
1561
1567int ships_load( void )
1568{
1569 char **ship_files;
1570 int nfiles;
1571#if DEBUGGING
1572 Uint32 time = SDL_GetTicks();
1573#endif /* DEBUGGING */
1574 ThreadQueue *tq = vpool_create();
1576
1577 /* Validity. */
1578 ss_check();
1579
1580 ship_files = ndata_listRecursive( SHIP_DATA_PATH );
1581 nfiles = array_size( ship_files );
1582
1583 /* Initialize stack if needed. */
1584 if ( ship_stack == NULL )
1585 ship_stack = array_create_size( Ship, nfiles );
1586
1587 /* First pass to find what ships we have to load. */
1588 for ( int i = 0; i < nfiles; i++ ) {
1589 if ( ndata_matchExt( ship_files[i], "xml" ) ) {
1590 ShipThreadData *td = &array_grow( &shipdata );
1591 memset( td, 0, sizeof( ShipThreadData ) );
1592 td->filename = ship_files[i];
1593 } else
1594 free( ship_files[i] );
1595 }
1596 array_free( ship_files );
1597
1598 /* Enqueue the jobs after the data array is done. */
1599 SDL_GL_MakeCurrent( gl_screen.window, NULL );
1600 for ( int i = 0; i < array_size( shipdata ); i++ )
1601 vpool_enqueue( tq, ship_parseThread, &shipdata[i] );
1602 /* Wait until done processing. */
1603 vpool_wait( tq );
1604 vpool_cleanup( tq );
1605 SDL_GL_MakeCurrent( gl_screen.window, gl_screen.context );
1606
1607 /* Properly load the data. */
1608 for ( int i = 0; i < array_size( shipdata ); i++ ) {
1609 ShipThreadData *td = &shipdata[i];
1610 if ( !td->ret )
1612 free( td->filename );
1613 }
1614 array_free( shipdata );
1615
1616 /* Sort so we can use ship_get. */
1617 qsort( ship_stack, array_size( ship_stack ), sizeof( Ship ), ship_cmp );
1618
1619 /* Now we do the second pass to resolve inheritance. */
1620 for ( int i = array_size( ship_stack ) - 1; i >= 0; i-- ) {
1621 Ship *s = &ship_stack[i];
1622 int ret = ship_parse( s, NULL, 0 );
1623 if ( ret )
1624 array_erase( &ship_stack, &s[0], &s[1] );
1625 }
1626
1627#if DEBUGGING
1628 /* Check to see if there are name collisions. */
1629 for ( int i = 1; i < array_size( ship_stack ); i++ )
1630 if ( strcmp( ship_stack[i - 1].name, ship_stack[i].name ) == 0 )
1631 WARN( _( "Duplicated ship name '%s' detected!" ), ship_stack[i].name );
1632#endif /* DEBUGGING */
1633
1634 /* Shrink stack. */
1636
1637 /* Second pass to load Lua. */
1638 for ( int i = 0; i < array_size( ship_stack ); i++ ) {
1639 Ship *s = &ship_stack[i];
1640 /* Update max size. */
1641 max_size = MAX( max_size, s->size );
1642 if ( s->lua_file == NULL )
1643 continue;
1644
1645 nlua_env env;
1646 size_t sz;
1647 char *dat = ndata_read( s->lua_file, &sz );
1648 if ( dat == NULL ) {
1649 WARN( _( "Ship '%s' failed to read Lua '%s'!" ), s->name,
1650 s->lua_file );
1651 continue;
1652 }
1653
1654 env = nlua_newEnv( s->lua_file );
1655 s->lua_env = env;
1656 /* TODO limit libraries here. */
1657 nlua_loadStandard( env );
1658 nlua_loadGFX( env );
1659 nlua_loadCamera( env );
1660
1661 /* Run code. */
1662 if ( nlua_dobufenv( env, dat, sz, s->lua_file ) != 0 ) {
1663 WARN( _( "Ship '%s' Lua error:\n%s" ), s->name,
1664 lua_tostring( naevL, -1 ) );
1665 lua_pop( naevL, 1 );
1666 nlua_freeEnv( s->lua_env );
1667 free( dat );
1668 s->lua_env = LUA_NOREF;
1669 continue;
1670 }
1671 free( dat );
1672
1673 /* Check functions as necessary. */
1674 nlua_getenv( naevL, env, "update_dt" );
1675 if ( !lua_isnoneornil( naevL, -1 ) )
1676 s->lua_dt = luaL_checknumber( naevL, -1 );
1677 lua_pop( naevL, 1 );
1678 s->lua_descextra = nlua_refenvtype( env, "descextra", LUA_TFUNCTION );
1679 s->lua_init = nlua_refenvtype( env, "init", LUA_TFUNCTION );
1680 s->lua_cleanup = nlua_refenvtype( env, "cleanup", LUA_TFUNCTION );
1681 s->lua_update = nlua_refenvtype( env, "update", LUA_TFUNCTION );
1682 s->lua_explode_init =
1683 nlua_refenvtype( env, "explode_init", LUA_TFUNCTION );
1685 nlua_refenvtype( env, "explode_update", LUA_TFUNCTION );
1686
1687 /* We're just going to run the script and paste here for now. */
1688 if ( s->lua_descextra != LUA_NOREF ) {
1689 free( s->desc_extra );
1690 s->desc_extra = NULL;
1691 lua_rawgeti( naevL, LUA_REGISTRYINDEX, s->lua_descextra ); /* f */
1692 lua_pushnil( naevL ); /* f, p */
1693 lua_pushship( naevL, s ); /* f, p, s */
1694 if ( nlua_pcall( s->lua_env, 2, 1 ) ) { /* */
1695 lua_pop( naevL, 1 );
1696 } else if ( lua_isnoneornil( naevL, -1 ) ) {
1697 /* Case no return we just pass nothing. */
1698 lua_pop( naevL, 1 );
1699 } else {
1700 s->desc_extra = strdup( luaL_checkstring( naevL, -1 ) );
1701 lua_pop( naevL, 1 );
1702 }
1703 }
1704 }
1705
1706 /* Debugging timings. */
1707 if ( conf.devmode ) {
1708 DEBUG( n_( "Loaded %d Ship in %.3f s", "Loaded %d Ships in %.3f s",
1710 array_size( ship_stack ), ( SDL_GetTicks() - time ) / 1000. );
1711 } else
1712 DEBUG(
1713 n_( "Loaded %d Ship", "Loaded %d Ships", array_size( ship_stack ) ),
1715
1716 ships_resize();
1717 return 0;
1718}
1719
1720void ships_resize( void )
1721{
1722 if ( ship_aa_scale > 0. ) {
1723 for ( int i = 0; i < SHIP_FBO; i++ ) {
1724 glDeleteFramebuffers( 1, &ship_fbo[i] );
1725 glDeleteTextures( 1, &ship_tex[i] );
1726 glDeleteTextures( 1, &ship_texd[i] );
1727 }
1728 }
1729
1730 /* Set up OpenGL rendering stuff. */
1731 ship_aa_scale = ship_aa_scale_base / gl_screen.scale;
1732 ship_fbos = ceil( ship_aa_scale * max_size );
1733 for ( int i = 0; i < SHIP_FBO; i++ ) {
1734 gl_fboCreate( &ship_fbo[i], &ship_tex[i], ship_fbos, ship_fbos );
1735 gl_fboAddDepth( ship_fbo[i], &ship_texd[i], ship_fbos, ship_fbos );
1736 }
1737 gl_checkErr();
1738}
1739
1743void ships_free( void )
1744{
1745 /* Clean up opengl. */
1746 for ( int i = 0; i < SHIP_FBO; i++ ) {
1747 glDeleteFramebuffers( 1, &ship_fbo[i] );
1748 glDeleteTextures( 1, &ship_tex[i] );
1749 glDeleteTextures( 1, &ship_texd[i] );
1750 }
1751
1752 /* Now ships. */
1753 for ( int i = 0; i < array_size( ship_stack ); i++ ) {
1754 Ship *s = &ship_stack[i];
1755
1756 /* Free stored strings. */
1757 free( s->inherits );
1758 free( s->name );
1759 free( s->class_display );
1760 free( s->description );
1761 free( s->desc_extra );
1762 free( s->base_type );
1763 free( s->base_path );
1764 free( s->fabricator );
1765 free( s->license );
1766 free( s->cond );
1767 free( s->condstr );
1768 free( s->desc_stats );
1769
1770 /* Free outfits. */
1771 for ( int j = 0; j < array_size( s->outfit_structure ); j++ )
1772 ship_freeSlot( &s->outfit_structure[j] );
1773 for ( int j = 0; j < array_size( s->outfit_utility ); j++ )
1774 ship_freeSlot( &s->outfit_utility[j] );
1775 for ( int j = 0; j < array_size( s->outfit_weapon ); j++ )
1776 ship_freeSlot( &s->outfit_weapon[j] );
1781
1782 ss_free( s->stats );
1783
1784 /* Free graphics. */
1785 gltf_free( s->gfx_3d );
1789 free( s->gfx_comm );
1790 for ( int j = 0; j < array_size( s->gfx_overlays ); j++ )
1793 free( s->gfx_path );
1794 free( s->polygon_path );
1795
1796 /* Free collision polygons. */
1797 poly_free( &s->polygon );
1798
1799 /* Free trail emitters. */
1801
1802 /* Free tags. */
1803 for ( int j = 0; j < array_size( s->tags ); j++ )
1804 free( s->tags[j] );
1805 array_free( s->tags );
1806
1807 /* Free Lua. */
1808 nlua_freeEnv( s->lua_env );
1809 s->lua_env = LUA_NOREF;
1810 free( s->lua_file );
1811 }
1812
1814 ship_stack = NULL;
1815}
1816
1817static void ship_freeSlot( ShipOutfitSlot *s )
1818{
1819 outfit_freeSlot( &s->slot );
1820 free( s->name );
1821}
1822
1826double ship_maxSize( void )
1827{
1828 return max_size;
1829}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
Definition array.h:214
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:148
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition array.h:160
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:134
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
Definition array.h:206
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void poly_load(CollPoly *polygon, xmlNodePtr base, const char *name)
Loads a polygon from an xml node.
Definition collision.c:37
const glColour * faction_colour(int f)
Gets the colour of the faction.
Definition faction.c:494
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:209
mat4 mat4_identity(void)
Creates an identity matrix.
Definition mat4.c:335
void mat4_rotate(mat4 *m, double angle, double x, double y, double z)
Multiplies the given matrix by a rotation. (Follows the right-hand rule.)
Definition mat4.c:216
mat4 mat4_ortho(double left, double right, double bottom, double top, double nearVal, double farVal)
Creates an orthographic projection matrix.
Definition mat4.c:347
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Definition naev.c:640
double elapsed_time_mod
Definition naev.c:117
int naev_shouldRenderLoadscreen(void)
Whether or not we want to render the loadscreen.
Definition naev.c:596
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
#define MAX(x, y)
Definition naev.h:37
#define PATH_MAX
Definition naev.h:57
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition ndata.c:207
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
Definition ndata.c:420
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:286
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition nlua.c:914
int nlua_refenvtype(nlua_env env, const char *name, int type)
Gets the reference of a global in a lua environment if it matches a type.
Definition nlua.c:1047
lua_State * naevL
Definition nlua.c:54
int nlua_loadCamera(nlua_env env)
Loads the camera library.
Definition nlua_camera.c:48
int nlua_loadGFX(nlua_env env)
Loads the graphics library.
Definition nlua_gfx.c:112
const Ship ** lua_pushship(lua_State *L, const Ship *ship)
Pushes a ship on the stack.
Definition nlua_ship.c:193
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:69
glTexture * xml_parseTexture(xmlNodePtr node, const char *path, int defsx, int defsy, const unsigned int flags)
Parses a texture handling the sx and sy elements.
Definition nxml.c:25
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:70
glInfo gl_screen
Definition opengl.c:47
void gl_renderShader(double x, double y, double w, double h, double r, const SimpleShader *shd, const glColour *c, int center)
Renders a simple shader.
void gl_renderTexture(const glTexture *texture, double x, double y, double w, double h, double tx, double ty, double tw, double th, const glColour *c, double angle)
Texture blitting backend.
void gl_renderTextureInterpolate(const glTexture *ta, const glTexture *tb, double inter, double x, double y, double w, double h, double tx, double ty, double tw, double th, const glColour *c)
Texture blitting backend for interpolated texture.
void gl_renderTextureRawH(GLuint texture, const mat4 *projection, const mat4 *tex_mat, const glColour *c)
Texture blitting backend.
void gl_renderTextureInterpolateRawH(GLuint ta, GLuint tb, double inter, const mat4 *projection, const mat4 *tex_mat, const glColour *c)
Texture blitting backend for interpolated texture.
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition opengl_tex.c:891
glTexture * gl_newSprite(const char *path, const int sx, const int sy, const unsigned int flags)
Loads the texture immediately, but also sets it as a sprite.
Definition opengl_tex.c:785
USE_RESULT glTexture * gl_rawTexture(const char *name, GLuint texid, double w, double h)
Creates a texture from a raw opengl index.
Definition opengl_tex.c:917
int gl_fboCreate(GLuint *fbo, GLuint *tex, GLsizei width, GLsizei height)
Creates a framebuffer and its associated texture.
Definition opengl_tex.c:268
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:587
int gl_fboAddDepth(GLuint fbo, GLuint *tex, GLsizei width, GLsizei height)
Adds a depth attachment to an FBO.
Definition opengl_tex.c:313
void gl_getSpriteFromDir(int *x, int *y, int sx, int sy, double dir)
Sets x and y to be the appropriate sprite for glTexture using dir.
Definition opengl_tex.c:977
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:835
void gl_vboActivateAttribOffset(gl_vbo *vbo, GLuint index, GLuint offset, GLint size, GLenum type, GLsizei stride)
Activates a VBO's offset.
Definition opengl_vbo.c:224
const Outfit * outfit_get(const char *name)
Gets an outfit by name.
Definition outfit.c:223
OutfitSlotSize outfit_toSlotSize(const char *s)
Gets the outfit slot size from a human readable string.
Definition outfit.c:544
int outfit_licenseExists(const char *name)
Checks to see if a license exists.
Definition outfit.c:3321
void outfit_freeSlot(OutfitSlot *s)
Frees an outfit slot.
Definition outfit.c:1246
static const double c[]
Definition rng.c:256
int ship_size(const Ship *s)
Gets the size of the ship.
Definition ship.c:526
ShipClass ship_classFromString(const char *str)
Gets the machine ship class identifier from a human readable string.
Definition ship.c:265
static int ship_parse(Ship *temp, const char *filename, int firstpass)
Extracts the in-game ship from an XML node.
Definition ship.c:893
static int ship_parseSlot(Ship *temp, ShipOutfitSlot *slot, OutfitSlotType type, xmlNodePtr node)
Parses a slot for a ship.
Definition ship.c:803
static Ship * ship_stack
Definition ship.c:59
static int ship_loadSpaceImage(Ship *temp, const char *str, int sx, int sy)
Loads the space graphics for a ship from an image.
Definition ship.c:568
const char * ship_class(const Ship *s)
Gets the ship's class name in human readable form.
Definition ship.c:192
static int ship_loadPLG(Ship *temp, const char *buf)
Loads the collision polygon for a ship.
Definition ship.c:754
static void ship_renderFramebuffer3D(const Ship *s, GLuint fbo, double size, double fw, double fh, double engine_glow, double t, const glColour *c, const Lighting *L, const mat4 *H, int blit, unsigned int flags)
Renders a 3D ship to a framebuffer.
Definition ship.c:1354
const char * ship_classDisplay(const Ship *s)
Gets the ship's display class in human readable form.
Definition ship.c:203
credits_t ship_basePrice(const Ship *s)
Gets the ship's base price (no outfits).
Definition ship.c:295
static int ship_parseThread(void *ptr)
Wrapper for threaded loading.
Definition ship.c:1548
credits_t ship_buyPrice(const Ship *s)
The ship buy price, includes default outfits.
Definition ship.c:303
double ship_maxSize(void)
Gets the maximum size of a ship.
Definition ship.c:1826
const Ship * ship_getW(const char *name)
Gets a ship based on its name without warning.
Definition ship.c:113
#define SHIP_ENGINE
Definition ship.c:38
int ships_load(void)
Loads all the ships in the data files.
Definition ship.c:1567
static int ship_cmp(const void *p1, const void *p2)
Compares two ship pointers for qsort.
Definition ship.c:86
const Ship * ship_getAll(void)
Gets the array (array.h) of all ships.
Definition ship.c:134
int ship_gfxLoadNeeded(void)
Tries to load the graphics for all ships that need it.
Definition ship.c:603
static int ship_loadEngineImage(Ship *temp, const char *str, int sx, int sy)
Loads the space graphics for a ship from an image.
Definition ship.c:586
void ships_free(void)
Frees all the ships.
Definition ship.c:1743
glTexture * ship_gfxComm(const Ship *s, int size, double tilt, double dir, const Lighting *Lscene)
Loads the ship's comm graphic.
Definition ship.c:418
int ship_compareTech(const void *arg1, const void *arg2)
Comparison function for qsort().
Definition ship.c:142
const char * ship_classToString(ShipClass class)
Gets the ship class name in human readable form.
Definition ship.c:216
#define STATS_DESC_MAX
Definition ship.c:48
int ship_gfxLoaded(const Ship *s)
Checks to see if a ship has loaded graphics.
Definition ship.c:595
#define SHIP_COMM
Definition ship.c:40
int ship_gfxAnimated(const Ship *s)
Returns whether or not the ship has animated graphics.
Definition ship.c:513
void ship_renderFramebuffer(const Ship *s, GLuint fbo, double fw, double fh, double dir, double engine_glow, double tilt, double r, int sx, int sy, const glColour *c, const Lighting *L)
Renders a ship to a framebuffer.
Definition ship.c:1489
glTexture * ship_gfxStore(const Ship *s, int size, double dir, double updown, double glow)
Get the store gfx.
Definition ship.c:383
const Ship * ship_get(const char *name)
Gets a ship based on its name.
Definition ship.c:99
const char * ship_existsCase(const char *name)
Checks to see if an ship exists matching name (case insensitive).
Definition ship.c:123
int ship_gfxLoad(Ship *s)
Loads the graphics for a ship if necessary.
Definition ship.c:628
int ss_statsListDesc(const ShipStatList *ll, char *buf, int len, int newline)
Writes the ship statistics description.
Definition shipstats.c:820
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition shipstats.c:934
int ss_statsMergeFromList(ShipStats *stats, const ShipStatList *list)
Updates a stat structure from a stat list.
Definition shipstats.c:666
int ss_statsInit(ShipStats *stats)
Initializes a stat structure.
Definition shipstats.c:490
int ss_check(void)
Checks for validity.
Definition shipstats.c:474
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
Definition shipstats.c:353
int ss_sort(ShipStatList **ll)
Sorts the ship stats, useful if doing saving stuff.
Definition shipstats.c:442
int sp_locked(unsigned int spid)
Gets whether or not a slot property is locked.
Definition slots.c:205
unsigned int sp_get(const char *name)
Gets the id of a slot property.
Definition slots.c:139
int sp_required(unsigned int spid)
Gets whether or not a slot property is required.
Definition slots.c:185
int sp_exclusive(unsigned int spid)
Gets whether or not a slot property is exclusive.
Definition slots.c:195
int sp_visible(unsigned int spid)
Whether or not the slot should be visible even if locked.
Definition slots.c:215
int sound_get(const char *name)
Gets the buffer to sound of name.
Definition sound.c:761
const TrailSpec * trailSpec_get(const char *name)
Gets a trail spec by name.
Definition spfx.c:1396
vec3 pos
Definition gltf.h:176
Defines a complete object.
Definition gltf.h:182
int scene_body
Definition gltf.h:196
GltfMount * mounts
Definition gltf.h:200
int scene_engine
Definition gltf.h:197
GltfTrail * trails
Definition gltf.h:199
size_t nanimations
Definition gltf.h:193
char * generator
Definition gltf.h:169
vec3 pos
Definition gltf.h:170
double ambient_b
Definition gltf.h:218
double intensity
Definition gltf.h:222
OutfitSlotSize size
Definition outfit.h:143
int exclusive
Definition outfit.h:141
unsigned int spid
Definition outfit.h:140
OutfitSlotType type
Definition outfit.h:142
A ship outfit, depends radically on the type.
Definition outfit.h:372
credits_t price
Definition outfit.h:391
Represents a ship weapon mount point.
Definition ship.h:64
vec3 pos
Definition ship.h:65
Ship outfit slot.
Definition ship.h:71
int exclusive
Definition ship.h:74
int required
Definition ship.h:75
const Outfit * data
Definition ship.h:78
int visible
Definition ship.h:77
char * name
Definition ship.h:73
ShipMount mount
Definition ship.h:79
OutfitSlot slot
Definition ship.h:72
int locked
Definition ship.h:76
Represents relative ship statistics as a linked list.
Definition shipstats.h:198
struct ShipStatList_ * next
Definition shipstats.h:199
Structure for threaded loading.
Definition ship.c:53
char * filename
Definition ship.c:54
Ship ship
Definition ship.c:55
Ship trail emitter.
Definition ship.h:88
const TrailSpec * trail_spec
Definition ship.h:91
unsigned int flags
Definition ship.h:90
Represents a space ship.
Definition ship.h:97
double shield_regen
Definition ship.h:142
double dt_default
Definition ship.h:136
double cap_cargo
Definition ship.h:135
char * desc_extra
Definition ship.h:122
glTexture * gfx_space
Definition ship.h:154
ShipStats stats_array
Definition ship.h:182
char * license
Definition ship.h:116
char * name
Definition ship.h:100
int sound
Definition ship.h:167
int fuel
Definition ship.h:133
void * rawdata
Definition ship.h:98
char * fabricator
Definition ship.h:120
char * description
Definition ship.h:121
int faction
Definition ship.h:108
int lua_init
Definition ship.h:193
GltfObject * gfx_3d
Definition ship.h:153
char * base_type
Definition ship.h:101
char * lua_file
Definition ship.h:188
char * class_display
Definition ship.h:107
credits_t price
Definition ship.h:115
int lua_update
Definition ship.h:195
double energy_regen
Definition ship.h:144
double armour
Definition ship.h:139
int fuel_consumption
Definition ship.h:134
double lua_dt
Definition ship.h:191
double armour_regen
Definition ship.h:140
CollPoly polygon
Definition ship.h:164
int noengine
Definition ship.h:152
int crew
Definition ship.h:130
ShipStatList * stats
Definition ship.h:181
double dmg_absorb
Definition ship.h:145
double engine_pitch
Definition ship.h:168
char * condstr
Definition ship.h:119
char * cond
Definition ship.h:117
glTexture * _gfx_store
Definition ship.h:156
int points
Definition ship.h:110
int lua_descextra
Definition ship.h:192
double cpu
Definition ship.h:132
double speed
Definition ship.h:127
ShipOutfitSlot * outfit_utility
Definition ship.h:174
double turn
Definition ship.h:126
char * desc_stats
Definition ship.h:180
char ** tags
Definition ship.h:185
Outfit const ** outfit_intrinsic
Definition ship.h:176
int rarity
Definition ship.h:111
char * inherits
Definition ship.h:99
glTexture * gfx_engine
Definition ship.h:155
double accel
Definition ship.h:125
int lua_cleanup
Definition ship.h:194
ShipOutfitSlot * outfit_weapon
Definition ship.h:175
nlua_env lua_env
Definition ship.h:190
char * polygon_path
Definition ship.h:151
double size
Definition ship.h:149
double energy
Definition ship.h:143
char * gfx_comm
Definition ship.h:157
char * base_path
Definition ship.h:103
ShipTrailEmitter * trail_emitters
Definition ship.h:159
int lua_explode_init
Definition ship.h:196
glTexture ** gfx_overlays
Definition ship.h:158
double shield
Definition ship.h:141
char * gfx_path
Definition ship.h:150
ShipClass class
Definition ship.h:105
double mass
Definition ship.h:131
ShipOutfitSlot * outfit_structure
Definition ship.h:172
int lua_explode_update
Definition ship.h:197
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:43
double sw
Definition opengl_tex.h:53
double sh
Definition opengl_tex.h:54
double w
Definition opengl_tex.h:47
uint8_t flags
Definition opengl_tex.h:64
double srh
Definition opengl_tex.h:56
double sy
Definition opengl_tex.h:52
double h
Definition opengl_tex.h:48
double srw
Definition opengl_tex.h:55
Definition mat4.h:12