maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
retroglu.h
Go to the documentation of this file.
1
2#ifndef RETROGLU_H
3#define RETROGLU_H
4
5/* TODO */
6#ifndef MAUG_CONST
7# define MAUG_CONST const
8#endif /* !MAUG_CONST */
9
19#define RETROGLU_PARSER_ERROR -1
20
21#ifndef RETROGLU_PARSER_TOKEN_SZ_MAX
22# define RETROGLU_PARSER_TOKEN_SZ_MAX 32
23#endif /* !RETROGLU_PARSER_TOKEN_SZ_MAX */
24
25#ifndef RETROGLU_TRACE_LVL
26# define RETROGLU_TRACE_LVL 0
27#endif /* !RETROGLU_TRACE_LVL */
28
29#ifndef RETROGLU_SPRITE_TEX_FRAMES_SZ
30# define RETROGLU_SPRITE_TEX_FRAMES_SZ 10
31#endif /* !RETROGLU_SPRITE_TEX_FRAMES_SZ */
32
33#ifndef MAUG_OS_NDS
34# define glShininessf( side, light, f ) glMaterialf( side, light, f )
35#endif /* MAUG_OS_NDS */
36
47#define RETROGLU_PARSER_STATE_NONE 0
48#define RETROGLU_PARSER_STATE_VERTEX_X 1
49#define RETROGLU_PARSER_STATE_VERTEX_Y 2
50#define RETROGLU_PARSER_STATE_VERTEX_Z 3
51#define RETROGLU_PARSER_STATE_COMMENT 4
52#define RETROGLU_PARSER_STATE_FACE_TOKEN 5
53#define RETROGLU_PARSER_STATE_FACE_VERTEX 6
54#define RETROGLU_PARSER_STATE_FACE_TEXTURE 7
55#define RETROGLU_PARSER_STATE_FACE_NORMAL 8
56#define RETROGLU_PARSER_STATE_FACE_MATERIAL 9
57#define RETROGLU_PARSER_STATE_MATERIAL_NAME 10
58#define RETROGLU_PARSER_STATE_MATERIAL_AMB 11
59#define RETROGLU_PARSER_STATE_MATERIAL_DIF 12
60#define RETROGLU_PARSER_STATE_MATERIAL_SPEC 13
61#define RETROGLU_PARSER_STATE_MATERIAL_LIB 14
62#define RETROGLU_PARSER_STATE_MTL_KD_R 15
63#define RETROGLU_PARSER_STATE_MTL_KD_G 16
64#define RETROGLU_PARSER_STATE_MTL_KD_B 17
65#define RETROGLU_PARSER_STATE_VNORMAL_X 18
66#define RETROGLU_PARSER_STATE_VNORMAL_Y 19
67#define RETROGLU_PARSER_STATE_VNORMAL_Z 20
68#define RETROGLU_PARSER_STATE_VTEXTURE_X 21
69#define RETROGLU_PARSER_STATE_VTEXTURE_Y 22
70#define RETROGLU_PARSER_STATE_VTEXTURE_Z 23
71#define RETROGLU_PARSER_STATE_MTL_KA_R 24
72#define RETROGLU_PARSER_STATE_MTL_KA_G 25
73#define RETROGLU_PARSER_STATE_MTL_KA_B 26
74#define RETROGLU_PARSER_STATE_MTL_KS_R 27
75#define RETROGLU_PARSER_STATE_MTL_KS_G 28
76#define RETROGLU_PARSER_STATE_MTL_KS_B 29
77#define RETROGLU_PARSER_STATE_MTL_KE_R 30
78#define RETROGLU_PARSER_STATE_MTL_KE_G 31
79#define RETROGLU_PARSER_STATE_MTL_KE_B 32
80#define RETROGLU_PARSER_STATE_MTL_NS 33
81
82 /* maug_retroglu_obj_fsm_states */
83
84 /* maug_retroglu_obj_fsm */
85
86#ifndef RETROGLU_FACE_VERTICES_SZ_MAX
87# define RETROGLU_FACE_VERTICES_SZ_MAX 3
88#endif /* !RETROGLU_FACE_VERTICES_SZ_MAX */
89
90#ifndef RETROGLU_MATERIAL_NAME_SZ_MAX
91# define RETROGLU_MATERIAL_NAME_SZ_MAX 32
92#endif /* !RETROGLU_MATERIAL_NAME_SZ_MAX */
93
94#ifndef RETROGLU_MATERIAL_LIB_SZ_MAX
95# define RETROGLU_MATERIAL_LIB_SZ_MAX 32
96#endif /* !RETROGLU_MATERIAL_LIB_SZ_MAX */
97
98typedef float RETROGLU_COLOR[4];
99
101 float x;
102 float y;
103 float z;
104};
105
107 float u;
108 float v;
109};
110
112 float ambient[4];
113 float diffuse[4];
114 float specular[4];
115 float emissive[4];
116 float specular_exp;
117 char name[RETROGLU_MATERIAL_NAME_SZ_MAX];
118};
119
127 uint16_t vertex_idxs[RETROGLU_FACE_VERTICES_SZ_MAX];
128 uint16_t vnormal_idxs[RETROGLU_FACE_VERTICES_SZ_MAX];
129 uint16_t vtexture_idxs[RETROGLU_FACE_VERTICES_SZ_MAX];
130 uint16_t vertex_idxs_sz;
131 uint16_t material_idx;
132};
133
134#define RETROGLU_VERTICES_SZ_MAX 1024
135#define RETROGLU_FACES_SZ_MAX 1024
136#define RETROGLU_MATERIALS_SZ_MAX 1024
137
139 uint8_t flags;
140 struct RETROGLU_VERTEX vertices[RETROGLU_VERTICES_SZ_MAX];
141 uint16_t vertices_sz;
142 struct RETROGLU_VERTEX vnormals[RETROGLU_VERTICES_SZ_MAX];
143 uint16_t vnormals_sz;
144 struct RETROGLU_VTEXTURE vtextures[RETROGLU_VERTICES_SZ_MAX];
145 uint16_t vtextures_sz;
150 struct RETROGLU_FACE faces[RETROGLU_FACES_SZ_MAX];
151 uint16_t faces_sz;
152 struct RETROGLU_MATERIAL materials[RETROGLU_MATERIALS_SZ_MAX];
153 uint16_t materials_sz;
154};
155
161#define RETROGLU_SPRITE_X 0
162#define RETROGLU_SPRITE_Y 1
163
164#ifndef RETROGLU_SPRITE_LIST_SZ_MAX
165# define RETROGLU_SPRITE_LIST_SZ_MAX 10
166#endif /* !RETROGLU_SPRITE_LIST_SZ_MAX */
167
174 uint32_t front_px;
175 uint32_t front_py;
176 uint32_t back_px;
177 uint32_t back_py;
178 uint32_t pw;
179 uint32_t ph;
180 uint8_t flags;
181};
182
184 float vertices_front[6][2];
185 float vtexture_front[6][2];
186 float vertices_back[6][2];
187 float vtexture_back[6][2];
188 float translate_x;
189 float translate_y;
190 int rotate_y;
191 RETROGLU_COLOR color;
192 struct RETROFLAT_BITMAP texture;
193#ifdef RETROGLU_NO_LISTS
194 struct RETROGLU_SPRITE_PARMS parms[RETROGLU_SPRITE_LIST_SZ_MAX];
195#else
196 GLint lists[RETROGLU_SPRITE_LIST_SZ_MAX];
197#endif /* RETROGLU_NO_LISTS */
198};
199
201 float vertices[6][2];
202 float vtexture[6][2];
203 int rotate_x;
204 struct RETROFLAT_BITMAP texture;
205};
206
207
208 /* maug_retroglu_sprite */
209
210#define RETROGLU_PROJ_ORTHO 0
211#define RETROGLU_PROJ_FRUSTUM 1
212
214 uint8_t proj;
215 float rzoom;
216 float near_plane;
217 float far_plane;
218 size_t screen_px_w;
219 size_t screen_px_h;
220};
221
222#ifdef RETROFLAT_API_LIBNDS
223# define retroglu_enable_lightning()
224# define retroglu_disable_lightning()
225#else
226# define retroglu_enable_lightning() glEnable( GL_LIGHTING )
227# define retroglu_disable_lightning() glDisable( GL_LIGHTING )
228#endif /* RETROFLAT_API_NDS */
229
241#define retroglu_push_overlay( x, y, x_f, y_f, aspect_f ) \
242 /* Switch to projection setup. */ \
243 glMatrixMode( GL_PROJECTION ); \
244 glPushMatrix(); \
245 /* Lighting makes overlay text hard to see. */ \
246 retroglu_disable_lightning(); \
247 /* Use ortho for overlay. */ \
248 glLoadIdentity(); \
249 aspect_f = (float)retroflat_screen_w() / (float)retroflat_screen_h(); \
250 /* Switch to ortho projection proportional to screen size. */ \
251 glOrtho( -1.0f * aspect_f, aspect_f, -1.0f, 1.0f, 0, 10.0f ); \
252 /* -1 to 1 is 2! */ \
253 aspect_f *= 2.0f; \
254 /* Assuming width > height for aspect ratio. */ \
255 x_f = ((x) * aspect_f / retroflat_screen_w()) - (aspect_f / 2); \
256 /* Vertical coords also need to be inverted because OpenGL. */ \
257 y_f = 1.0f - ((y) * 2.0f / retroflat_screen_h()); \
258
267#define retroglu_whf( w, h, w_f, h_f, aspect_f ) \
268 w_f = ((w) * aspect_f / retroflat_screen_w()); \
269 h_f = ((h) * 2.0f / retroflat_screen_h());
270
274#define retroglu_pop_overlay() \
275 glPopMatrix(); \
276 glMatrixMode( GL_MODELVIEW );
277
278 /* maug_retroglu_overlay */
279
280#define retroglu_tex_px_x_to_f( px, sprite ) \
281 ((px) * 1.0 / sprite->texture.tex.w)
282#define retroglu_tex_px_y_to_f( px, sprite ) \
283 ((px) * 1.0 / sprite->texture.tex.h)
284
285#define retroglu_scr_px_x_to_f( px ) \
286 (float)(((px) * 1.0 / (retroflat_screen_w() / 2)) - 1.0)
287#define retroglu_scr_px_y_to_f( py ) \
288 (float)(((py) * 1.0 / (retroflat_screen_h() / 2)) - 1.0)
289
290#define retroglu_set_sprite_tex( sprite, texture_id, bmp_w, bmp_h ) \
291 sprite->texture_id = texture_id; \
292 sprite->texture_w = bmp_w; \
293 sprite->texture_h = bmp_h;
294
295#define retroglu_set_sprite_color( sprite, color_in ) \
296 memcpy( (sprite)->color, (color_in), 3 * sizeof( float ) )
297
308#define retroglu_parser_state( parser, new_state ) \
309 debug_printf( \
310 RETROGLU_TRACE_LVL, "changing parser to state: %d", new_state ); \
311 (parser)->state = new_state;
312
316#define RETROGLU_OBJ_TOKENS( f ) \
317 f( "v", retroglu_token_vertice ) \
318 f( "vn", retroglu_token_vnormal ) \
319 f( "f", retroglu_token_face ) \
320 f( "usemtl", retroglu_token_usemtl ) \
321 f( "newmtl", retroglu_token_newmtl ) \
322 f( "mtllib", retroglu_token_mtllib ) \
323 f( "Kd", retroglu_token_kd ) \
324 f( "Ka", retroglu_token_ka ) \
325 f( "Ks", retroglu_token_ks ) \
326 f( "Ke", retroglu_token_ks ) \
327 f( "Ns", retroglu_token_ns )
328
329struct RETROGLU_PARSER;
330
335typedef int (*retroglu_mtl_cb)(
336 const char* filename, struct RETROGLU_PARSER* parser, void* data );
337
343 struct RETROGLU_OBJ* obj;
344 int state;
345 int material_idx;
346 char token[RETROGLU_PARSER_TOKEN_SZ_MAX];
347 size_t token_sz;
348 retroglu_mtl_cb load_mtl;
349 void* load_mtl_data;
350};
351
352typedef int (*retroglu_token_cb)( struct RETROGLU_PARSER* parser );
353
354void retroglu_init_scene( uint8_t flags );
355void retroglu_init_projection( struct RETROGLU_PROJ_ARGS* args );
356
364 struct RETROGLU_PARSER* parser, struct RETROGLU_OBJ* obj,
365 retroglu_mtl_cb load_mtl, void* load_mtl_data
366);
367
375retroglu_parse_obj_c( struct RETROGLU_PARSER* parser, unsigned char c );
376
377MERROR_RETVAL retroglu_parse_obj_file(
378 const char* filename, struct RETROGLU_PARSER* parser,
379 struct RETROGLU_OBJ* obj );
380
381 /* maug_retroglu_obj_fsm */
382
383void retroglu_draw_poly( struct RETROGLU_OBJ* obj );
384
385void retroglu_set_tile_clip(
386 struct RETROGLU_TILE* tile,
387 uint32_t px, uint32_t py, uint32_t pw, uint32_t ph, uint8_t flags );
388
389void retroglu_set_sprite_clip(
390 struct RETROGLU_SPRITE* sprite,
391 uint32_t front_px, uint32_t front_py, uint32_t back_px, uint32_t back_py,
392 uint32_t pw, uint32_t ph, uint8_t flags );
393
400
401void retroglu_init_sprite_vertices_scale(
402 struct RETROGLU_SPRITE* sprite, float scale );
403
404void retroglu_set_sprite_pos(
405 struct RETROGLU_SPRITE* sprite, uint32_t px, uint32_t py );
406
407void retroglu_tsrot_sprite( struct RETROGLU_SPRITE* sprite );
408
414
422 struct RETROGLU_SPRITE* sprite, int list_idx,
423 uint32_t front_px, uint32_t front_py, uint32_t back_px, uint32_t back_py,
424 uint32_t pw, uint32_t ph, uint8_t flags );
425
430void retroglu_jitrender_sprite( struct RETROGLU_SPRITE* sprite, int list_idx );
431
432void retroglu_free_sprite( struct RETROGLU_SPRITE* sprite );
433
434MERROR_RETVAL retroglu_init_glyph_tex();
435
436void retroglu_destroy_glyph_tex();
437
438void retroglu_string(
439 float x, float y, float z, const RETROGLU_COLOR color,
440 const char* str, size_t str_sz, const char* font_str, uint8_t flags );
441
442MERROR_RETVAL retroglu_check_errors( const char* desc );
443
444/* int retroglu_draw_lock( struct RETROFLAT_BITMAP* bmp ); */
445
446int retroglu_draw_release( struct RETROFLAT_BITMAP* bmp );
447
448MERROR_RETVAL retroglu_blit_bitmap(
449 struct RETROFLAT_BITMAP* target, struct RETROFLAT_BITMAP* src,
450 size_t s_x, size_t s_y, size_t d_x, size_t d_y, size_t w, size_t h,
451 int16_t instance );
452
453#ifdef RETROGLU_C
454
455# define RETROFLAT_COLOR_TABLE_GL( idx, name_l, name_u, r, g, b, cgac, cgad ) \
456 MAUG_CONST float RETROGLU_COLOR_ ## name_u[] = { \
457 (float)((float)r * 1.0f / 255.0f), \
458 (float)((float)g * 1.0f / 255.0f), \
459 (float)((float)b * 1.0f / 255.0f) };
460
461RETROFLAT_COLOR_TABLE( RETROFLAT_COLOR_TABLE_GL )
462
463# define RETROGLU_OBJ_TOKEN_STRINGS( token, callback ) token,
464
465int retroglu_token_vertice( struct RETROGLU_PARSER* parser ) {
466 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_VERTEX_X );
467 return RETROFLAT_OK;
468}
469
470int retroglu_token_vnormal( struct RETROGLU_PARSER* parser ) {
471 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_VNORMAL_X );
472 return RETROFLAT_OK;
473}
474
475int retroglu_token_face( struct RETROGLU_PARSER* parser ) {
476 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_FACE_VERTEX );
477 parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz = 0;
478 return RETROFLAT_OK;
479}
480
481int retroglu_token_usemtl( struct RETROGLU_PARSER* parser ) {
482 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_FACE_MATERIAL );
483 return RETROFLAT_OK;
484}
485
486int retroglu_token_newmtl( struct RETROGLU_PARSER* parser ) {
487 /* Set default lighting alpha to non-transparent. */
488 parser->obj->materials[parser->obj->materials_sz].ambient[3] = 1.0f;
489 parser->obj->materials[parser->obj->materials_sz].diffuse[3] = 1.0f;
490 parser->obj->materials[parser->obj->materials_sz].specular[3] = 1.0f;
491 parser->obj->materials[parser->obj->materials_sz].emissive[3] = 1.0f;
492 parser->obj->materials[parser->obj->materials_sz].specular_exp = 0;
493 parser->obj->materials_sz++;
494 assert( parser->obj->materials_sz <= RETROGLU_MATERIALS_SZ_MAX );
495 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_MATERIAL_NAME );
496 return RETROFLAT_OK;
497}
498
499int retroglu_token_mtllib( struct RETROGLU_PARSER* parser ) {
500 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_MATERIAL_LIB );
501 return RETROFLAT_OK;
502}
503
504int retroglu_token_kd( struct RETROGLU_PARSER* parser ) {
505 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_MTL_KD_R );
506 return RETROFLAT_OK;
507}
508
509int retroglu_token_ka( struct RETROGLU_PARSER* parser ) {
510 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_MTL_KA_R );
511 return RETROFLAT_OK;
512}
513
514int retroglu_token_ks( struct RETROGLU_PARSER* parser ) {
515 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_MTL_KS_R );
516 return RETROFLAT_OK;
517}
518
519int retroglu_token_ke( struct RETROGLU_PARSER* parser ) {
520 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_MTL_KE_R );
521 return RETROFLAT_OK;
522}
523
524int retroglu_token_ns( struct RETROGLU_PARSER* parser ) {
525 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_MTL_NS );
526 return RETROFLAT_OK;
527}
528
529char* g_retroglu_token_strings[] = {
530 RETROGLU_OBJ_TOKENS( RETROGLU_OBJ_TOKEN_STRINGS )
531 ""
532};
533
534# define RETROGLU_OBJ_TOKEN_CALLBACKS( token, callback ) callback,
535
536retroglu_token_cb g_retroglu_token_callbacks[] = {
537 RETROGLU_OBJ_TOKENS( RETROGLU_OBJ_TOKEN_CALLBACKS )
538 NULL
539};
540
541void retroglu_init_scene( uint8_t flags ) {
542 debug_printf( RETROGLU_TRACE_LVL, "initializing..." );
543
544#ifdef MAUG_OS_NDS
545 glMaterialShinyness();
546 glPolyFmt( POLY_ALPHA( 15 ) | POLY_CULL_BACK | POLY_FORMAT_LIGHT0 );
547#else
548 glEnable( GL_CULL_FACE );
549 glShadeModel( GL_SMOOTH );
550
551 /* Setup texture transparency. */
552 glEnable( GL_TEXTURE_2D );
553 glEnable( GL_BLEND );
554 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
555
556 /* Setup depth buffer so triangles in back are hidden. */
557 glEnable( GL_DEPTH_TEST );
558 glDepthMask( GL_TRUE );
559 glDepthFunc( GL_LESS );
560 glDepthRange( 0.0f, 1.0f );
561#endif /* !MAUG_OS_NDS */
562}
563
564void retroglu_init_projection( struct RETROGLU_PROJ_ARGS* args ) {
565 float aspect_ratio = 0;
566
567 if( 0 == args->screen_px_w ) {
568 debug_printf( 1,
569 "using assumed screen width: " SIZE_T_FMT, retroflat_screen_w() );
570 args->screen_px_w = retroflat_screen_w();
571 } else {
572 debug_printf( 1,
573 "using specified screen width: " SIZE_T_FMT, retroflat_screen_w() );
574 }
575 if( 0 == args->screen_px_h ) {
576 debug_printf( 1,
577 "using assumed screen height: " SIZE_T_FMT, retroflat_screen_h() );
578 args->screen_px_h = retroflat_screen_h();
579 } else {
580 debug_printf( 1,
581 "using specified screen height: " SIZE_T_FMT, retroflat_screen_h() );
582 }
583
584 /* Setup projection. */
585#ifdef MAUG_OS_NDS
586 glViewport( 0, 0, 255, 191 );
587#else
588 glViewport(
589 0, 0, (uint32_t)(args->screen_px_w), (uint32_t)(args->screen_px_h) );
590#endif
591 aspect_ratio = (float)(args->screen_px_w) / (float)(args->screen_px_h);
592
593 /* Switch to projection matrix for setup. */
594 glMatrixMode( GL_PROJECTION );
595
596 /* Zero everything out. */
597 glLoadIdentity();
598
599 /* Near plane can't be zero for frustum! */
600 assert( 0 != args->near_plane );
601
602 switch( args->proj ) {
603 case RETROGLU_PROJ_FRUSTUM:
604 /* This is really tweaky, and when it breaks, polygons seem to get drawn
605 * out of order? Still experimenting/researching. */
606 debug_printf( RETROGLU_TRACE_LVL, "aspect ratio: %f", aspect_ratio );
607 glFrustum(
608 /* The smaller these are, the closer it lets us get to the camera? */
609 -1.0f * args->rzoom * aspect_ratio, args->rzoom * aspect_ratio,
610 -1.0f * args->rzoom, args->rzoom,
611 args->near_plane, args->far_plane );
612 break;
613
614 case RETROGLU_PROJ_ORTHO:
615 /* This is much simpler/more forgiving than frustum. */
616 glOrtho(
617 -1.0f * args->rzoom * aspect_ratio,
618 args->rzoom * aspect_ratio,
619 -1.0f * args->rzoom, args->rzoom,
620 args->near_plane, args->far_plane );
621 break;
622 }
623
624 /* Revert to model matrix for later instructions (out of this scope). */
625 glMatrixMode( GL_MODELVIEW );
626}
627
629 struct RETROGLU_PARSER* parser, struct RETROGLU_OBJ* obj,
630 retroglu_mtl_cb load_mtl, void* load_mtl_data
631) {
632 parser->load_mtl = load_mtl;
633 parser->load_mtl_data = load_mtl_data;
634 parser->obj = obj;
635 assert( NULL != parser->obj );
636 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_NONE );
637 parser->token_sz = 0;
638}
639
640#define RETROGLU_TOKENS_VF( f ) \
641 f( "X", VERTEX_X, vertices, vertices_sz, x, VERTEX_Y ) \
642 f( "Y", VERTEX_Y, vertices, vertices_sz, y, VERTEX_Z ) \
643 f( "Z", VERTEX_Z, vertices, vertices_sz, z, NONE ) \
644 f( "normal X", VNORMAL_X, vnormals, vnormals_sz, x, VNORMAL_Y ) \
645 f( "normal Y", VNORMAL_Y, vnormals, vnormals_sz, y, VNORMAL_Z ) \
646 f( "normal Z", VNORMAL_Z, vnormals, vnormals_sz, z, NONE ) \
647 f( "mtl Kd R", MTL_KD_R, materials, materials_sz-1, diffuse[0], MTL_KD_G ) \
648 f( "mtl Kd G", MTL_KD_G, materials, materials_sz-1, diffuse[1], MTL_KD_B ) \
649 f( "mtl Kd B", MTL_KD_B, materials, materials_sz-1, diffuse[2], NONE ) \
650 f( "mtl Ka R", MTL_KA_R, materials, materials_sz-1, ambient[0], MTL_KA_G ) \
651 f( "mtl Ka G", MTL_KA_G, materials, materials_sz-1, ambient[1], MTL_KA_B ) \
652 f( "mtl Ka B", MTL_KA_B, materials, materials_sz-1, ambient[2], NONE ) \
653 f( "mtl Ks R", MTL_KS_R, materials, materials_sz-1, specular[0], MTL_KS_G ) \
654 f( "mtl Ks G", MTL_KS_G, materials, materials_sz-1, specular[1], MTL_KS_B ) \
655 f( "mtl Ks B", MTL_KS_B, materials, materials_sz-1, specular[2], NONE ) \
656 f( "mtl Ke R", MTL_KE_R, materials, materials_sz-1, emissive[0], MTL_KE_G ) \
657 f( "mtl Ke G", MTL_KE_G, materials, materials_sz-1, emissive[1], MTL_KE_B ) \
658 f( "mtl Ke B", MTL_KE_B, materials, materials_sz-1, emissive[2], NONE ) \
659 f( "mtl Ns", MTL_NS, materials, materials_sz-1, specular_exp, NONE )
660
661#define RETROGLU_TOKEN_PARSE_VF( desc, cond, array, sz, val, state_next ) \
662 } else if( RETROGLU_PARSER_STATE_ ## cond == parser->state ) { \
663 /* TODO: Maug replacement for C99 crutch. */ \
664 parser->obj->array[parser->obj->sz].val = strtod( parser->token, NULL ); \
665 debug_printf( RETROGLU_TRACE_LVL, "vertex %d " desc ": %f", \
666 parser->obj->sz, parser->obj->array[parser->obj->sz].val ); \
667 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_ ## state_next );
668
670retroglu_parse_token( struct RETROGLU_PARSER* parser ) {
671 int i = 0;
673
674 if( 0 == parser->token_sz ) {
675 /* Empty token. */
676 goto cleanup;
677 }
678
679 /* NULL-terminate token. */
680 parser->token[parser->token_sz] = '\0';
681
682 debug_printf( RETROGLU_TRACE_LVL, "token: %s", parser->token );
683
684 if( RETROGLU_PARSER_STATE_MATERIAL_LIB == parser->state ) {
685
686 debug_printf(
687 RETROGLU_TRACE_LVL, "parsing material lib: %s", parser->token );
688 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_NONE );
689 assert( NULL != parser->load_mtl );
690 return parser->load_mtl( parser->token, parser, parser->load_mtl_data );
691
692 RETROGLU_TOKENS_VF( RETROGLU_TOKEN_PARSE_VF )
693
694 /* TODO: Handle W. */
695
696 } else if( RETROGLU_PARSER_STATE_FACE_VERTEX == parser->state ) {
697 /* Parsing face vertex index. */
698 parser->obj->faces[parser->obj->faces_sz].vertex_idxs[
699 parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz] =
700 atoi( parser->token );
701
702 debug_printf( RETROGLU_TRACE_LVL, "face %d, vertex %d: %d",
703 parser->obj->faces_sz, parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz,
704 parser->obj->faces[parser->obj->faces_sz].vertex_idxs[
705 parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz] );
706
707 /* The new state is set in the parser below, as it could become
708 * RETROGLU_PARSER_STATE_FACE_NORMAL or RETROGLU_PARSER_STATE_NONE,
709 * depending on whether it's a whitespace/newline/slash after.
710 * Same for index incr.
711 */
712
713 } else if( RETROGLU_PARSER_STATE_FACE_NORMAL == parser->state ) {
714
715 /* Parsing face normal index. */
716 parser->obj->faces[parser->obj->faces_sz].vnormal_idxs[
717 parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz] =
718 atoi( parser->token );
719
720 debug_printf( RETROGLU_TRACE_LVL, "face %d, normal %d: %d",
721 parser->obj->faces_sz, parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz,
722 parser->obj->faces[parser->obj->faces_sz].vnormal_idxs[
723 parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz] );
724
725 /* The new state is set in the parser below, as it could become
726 * RETROGLU_PARSER_STATE_FACE_NORMAL or RETROGLU_PARSER_STATE_NONE,
727 * depending on whether it's a whitespace/newline/slash after.
728 * Same for index incr.
729 */
730
731 } else if( RETROGLU_PARSER_STATE_FACE_TEXTURE == parser->state ) {
732
733 /* Parsing face texture index. */
734 parser->obj->faces[parser->obj->faces_sz].vtexture_idxs[
735 parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz] =
736 atoi( parser->token );
737
738 debug_printf( RETROGLU_TRACE_LVL, "face %d, texture %d: %d",
739 parser->obj->faces_sz, parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz,
740 parser->obj->faces[parser->obj->faces_sz].vtexture_idxs[
741 parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz] );
742
743 /* The new state is set in the parser below, as it could become
744 * RETROGLU_PARSER_STATE_FACE_NORMAL or RETROGLU_PARSER_STATE_NONE,
745 * depending on whether it's a whitespace/newline/slash after.
746 * Same for index incr.
747 */
748
749
750 } else if( RETROGLU_PARSER_STATE_FACE_MATERIAL == parser->state ) {
751
752 /* Find the material index and assign it to the parser. */
753 for( i = 0 ; parser->obj->materials_sz > i ; i++ ) {
754 debug_printf(
755 RETROGLU_TRACE_LVL,
756 "%s vs %s", parser->obj->materials[i].name, parser->token );
757 if( 0 == strncmp(
758 parser->obj->materials[i].name, parser->token,
759 RETROGLU_MATERIAL_NAME_SZ_MAX
760 ) ) {
761 debug_printf( RETROGLU_TRACE_LVL, "using material: \"%s\" (%d)",
762 parser->obj->materials[i].name, i );
763 parser->material_idx = i;
764 break;
765 }
766 }
767 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_NONE );
768
769 } else if( RETROGLU_PARSER_STATE_MATERIAL_NAME == parser->state ) {
770
771 debug_printf(
772 RETROGLU_TRACE_LVL, "adding material: \"%s\" at idx: %d",
773 parser->token, parser->obj->materials_sz - 1 );
774 maug_strncpy(
775 parser->obj->materials[parser->obj->materials_sz - 1].name,
776 parser->token,
777 RETROGLU_MATERIAL_NAME_SZ_MAX );
778 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_NONE );
779
780 } else {
781 /* Check against generic tokens. */
782 while( '\0' != g_retroglu_token_strings[i][0] ) {
783 if(
784 parser->token_sz == maug_strlen( g_retroglu_token_strings[i] ) &&
785 0 == strncmp(
786 parser->token, g_retroglu_token_strings[i],
787 parser->token_sz )
788 ) {
789 retval = g_retroglu_token_callbacks[i]( parser );
790 goto cleanup;
791 }
792 i++;
793 }
794 }
795
796cleanup:
797
798 /* Reset token. */
799 parser->token_sz = 0;
800
801 return retval;
802}
803
805retroglu_append_token( struct RETROGLU_PARSER* parser, unsigned char c ) {
806 parser->token[parser->token_sz++] = c;
807
808 /* Protect against token overflow. */
809 if( parser->token_sz >= RETROGLU_PARSER_TOKEN_SZ_MAX ) {
810 debug_printf( RETROGLU_TRACE_LVL, "token out of bounds!" );
811 return RETROGLU_PARSER_ERROR;
812 }
813
814 return RETROFLAT_OK;
815}
816
818retroglu_parse_obj_c( struct RETROGLU_PARSER* parser, unsigned char c ) {
820
821 if(
822 RETROGLU_PARSER_STATE_COMMENT == parser->state && '\r' != c && '\n' != c
823 ) {
824 /* We're inside of a comment. */
825 return RETROFLAT_OK;
826 }
827
828 switch( c ) {
829 case '#':
830 /* Start of a comment. */
831 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_COMMENT );
832 break;
833
834 case '\r':
835 case '\n':
836 /* New line! End of a comment or token. */
837 if( RETROGLU_PARSER_STATE_COMMENT == parser->state ) {
838 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_NONE );
839 return RETROFLAT_OK;
840
841 } else if(
842 RETROGLU_PARSER_STATE_FACE_VERTEX == parser->state ||
843 RETROGLU_PARSER_STATE_FACE_TEXTURE == parser->state ||
844 RETROGLU_PARSER_STATE_FACE_NORMAL == parser->state
845 ) {
846 /* End of face. */
847 retval = retroglu_parse_token( parser );
848 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_NONE );
849
850 /* Use current parser material. */
851 parser->obj->faces[parser->obj->faces_sz].material_idx =
852 parser->material_idx;
853
854 /* Move to next face. */
855 parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz++;
856 parser->obj->faces_sz++; /* Newline means this face is done. */
857 assert( parser->obj->faces_sz <= RETROGLU_FACES_SZ_MAX );
858 return retval;
859
860 } else if( RETROGLU_PARSER_STATE_VNORMAL_Z == parser->state ) {
861
862 retval = retroglu_parse_token( parser );
863 /* End of vertex. */
864 parser->obj->vnormals_sz++;
865 assert( parser->obj->vnormals_sz <= RETROGLU_VERTICES_SZ_MAX );
866 return retval;
867
868 } else if( RETROGLU_PARSER_STATE_VERTEX_Z == parser->state ) {
869
870 retval = retroglu_parse_token( parser );
871 /* End of vertex. */
872 parser->obj->vertices_sz++;
873 assert( parser->obj->vertices_sz <= RETROGLU_VERTICES_SZ_MAX );
874 return retval;
875
876 } else {
877 return retroglu_parse_token( parser );
878 }
879
880 case '\t':
881 case ' ':
882 /* Whitespace. Inside of a comment or time for a new token. */
883 if( RETROGLU_PARSER_STATE_COMMENT == parser->state ) {
884 /* Do nothing on spaces in comments. */
885 return RETROFLAT_OK;
886
887 } else if(
888 RETROGLU_PARSER_STATE_FACE_VERTEX == parser->state ||
889 RETROGLU_PARSER_STATE_FACE_TEXTURE == parser->state ||
890 RETROGLU_PARSER_STATE_FACE_NORMAL == parser->state
891 ) {
892 /* A space means we're moving on to the next vertex! */
893 retval = retroglu_parse_token( parser );
894 parser->obj->faces[parser->obj->faces_sz].vertex_idxs_sz++;
895 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_FACE_VERTEX );
896 return retval;
897
898 } else if( RETROGLU_PARSER_STATE_VNORMAL_Z == parser->state ) {
899
900 retval = retroglu_parse_token( parser );
901 /* End of vertex. */
902 parser->obj->vnormals_sz++;
903 assert( parser->obj->vnormals_sz <= RETROGLU_VERTICES_SZ_MAX );
904 return retval;
905
906 } else if( RETROGLU_PARSER_STATE_VERTEX_Z == parser->state ) {
907
908 retval = retroglu_parse_token( parser );
909 /* End of vertex. */
910 parser->obj->vertices_sz++;
911 assert( parser->obj->vertices_sz <= RETROGLU_VERTICES_SZ_MAX );
912 return retval;
913
914 } else if( RETROGLU_PARSER_STATE_MTL_KD_B == parser->state ) {
915 retval = retroglu_parse_token( parser );
916 /* This tuple has a space after blue, so maybe alpha? */
917 /* TODO: Set alpha state. */
918 return retval;
919
920 } else {
921 return retroglu_parse_token( parser );
922 }
923
924 case '/':
925 if( RETROGLU_PARSER_STATE_FACE_VERTEX == parser->state ) {
926 retval = retroglu_parse_token( parser );
927 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_FACE_TEXTURE );
928 return retval;
929
930 } else if( RETROGLU_PARSER_STATE_FACE_TEXTURE == parser->state ) {
931 retval = retroglu_parse_token( parser );
932 retroglu_parser_state( parser, RETROGLU_PARSER_STATE_FACE_NORMAL );
933 return retval;
934 }
935
936 /* v/vt/vn/??? */
937 assert( RETROGLU_PARSER_STATE_FACE_NORMAL != parser->state );
938
939 /* If not part of a face, fall through to default append. */
940 return retroglu_append_token( parser, c );
941
942 default:
943 return retroglu_append_token( parser, c );
944 }
945
946 return RETROFLAT_OK;
947}
948
949MERROR_RETVAL retroglu_parse_obj_file(
950 const char* filename, struct RETROGLU_PARSER* parser,
951 struct RETROGLU_OBJ* obj
952) {
953 int auto_parser = 0; /* Did we provision parser? */
954 char filename_path[RETROFLAT_PATH_MAX + 1];
955 MERROR_RETVAL retval = MERROR_OK;
956 mfile_t obj_file;
957 char c;
958
959 if( NULL == parser ) {
960 parser = calloc( 1, sizeof( struct RETROGLU_PARSER ) );
961 assert( NULL != parser );
962 auto_parser = 1;
963 }
964
965 /* Build the path to the obj. */
966 memset( filename_path, '\0', RETROFLAT_PATH_MAX + 1 );
967 maug_snprintf( filename_path, RETROFLAT_PATH_MAX, "%s%c%s",
968 g_retroflat_state->assets_path, RETROFLAT_PATH_SEP, filename );
969
970 /* Open the file and allocate the buffer. */
971 retval = mfile_open_read( filename_path, &obj_file );
972 maug_cleanup_if_not_ok();
973
975 parser, obj, (retroglu_mtl_cb)retroglu_parse_obj_file, obj );
976
977 /* Parse the obj, byte by byte. */
978 while( mfile_has_bytes( &obj_file ) ) {
979 retval = obj_file.read_int( &obj_file, (uint8_t*)&c, 1, 0 );
980 maug_cleanup_if_not_ok();
981 retval = retroglu_parse_obj_c( parser, c );
982 maug_cleanup_if_not_ok();
983 }
984
985 if( auto_parser ) {
986 free( parser );
987 parser = NULL;
988 }
989
990 debug_printf(
991 RETROGLU_TRACE_LVL,
992 "parsed %s, %u vertices, %u materials",
993 filename_path, obj->vertices_sz, obj->materials_sz );
994
995cleanup:
996
997 return retval;
998}
999
1000void retroglu_draw_poly( struct RETROGLU_OBJ* obj ) {
1001 int i = 0;
1002 int j = 0;
1003
1004 glBegin( GL_TRIANGLES );
1005 for( i = 0 ; obj->faces_sz > i ; i++ ) {
1006
1007 /* TODO: Handle material on NDS. */
1008 glMaterialfv( GL_FRONT, GL_DIFFUSE,
1009 obj->materials[obj->faces[i].material_idx].diffuse );
1010 /*
1011 glMaterialfv( GL_FRONT, GL_AMBIENT,
1012 obj->materials[faces[i].material_idx].ambient );
1013 */
1014 glMaterialfv( GL_FRONT, GL_SPECULAR,
1015 obj->materials[obj->faces[i].material_idx].specular );
1016 glMaterialfv( GL_FRONT, GL_EMISSION,
1017 obj->materials[obj->faces[i].material_idx].emissive );
1018
1019 glColor3fv( obj->materials[obj->faces[i].material_idx].diffuse );
1020
1021 /* Use a specific macro here that can be overridden for e.g. the NDS. */
1022 glShininessf( GL_FRONT, GL_SHININESS,
1023 obj->materials[obj->faces[i].material_idx].specular_exp );
1024
1025 for( j = 0 ; obj->faces[i].vertex_idxs_sz > j ; j++ ) {
1026 assert( 0 < obj->faces[i].vertex_idxs[j] );
1027 assert( 3 == obj->faces[i].vertex_idxs_sz );
1028
1029 glNormal3f(
1030 obj->vnormals[obj->faces[i].vnormal_idxs[j] - 1].x,
1031 obj->vnormals[obj->faces[i].vnormal_idxs[j] - 1].y,
1032 obj->vnormals[obj->faces[i].vnormal_idxs[j] - 1].z );
1033
1034 glVertex3f(
1035 obj->vertices[obj->faces[i].vertex_idxs[j] - 1].x,
1036 obj->vertices[obj->faces[i].vertex_idxs[j] - 1].y,
1037 obj->vertices[obj->faces[i].vertex_idxs[j] - 1].z );
1038 }
1039
1040 }
1041 glEnd();
1042}
1043
1044void retroglu_set_tile_clip(
1045 struct RETROGLU_TILE* tile,
1046 uint32_t px, uint32_t py, uint32_t pw, uint32_t ph, uint8_t flags
1047) {
1048 /* Set vertices in terms of half the clip size so that rotation is around
1049 * the midpoint of the sprite, not the side!
1050 */
1051 float clip_tex_x = 0, /* Front tex X */
1052 clip_tex_y = 0, /* Front tex Y */
1053 clip_tex_w = 0,
1054 clip_tex_h = 0;
1055
1056 /* Setup texture tilesheet. */
1057
1058 clip_tex_x = retroglu_tex_px_x_to_f( px, tile );
1059 clip_tex_y = retroglu_tex_px_y_to_f( py, tile );
1060 clip_tex_w = retroglu_tex_px_x_to_f( pw, tile );
1061 clip_tex_h = retroglu_tex_px_y_to_f( ph, tile );
1062
1063 /* == Front Face Textures == */
1064
1065 /* Lower Left */
1066 tile->vtexture[0][RETROGLU_SPRITE_X] = clip_tex_x;
1067 tile->vtexture[0][RETROGLU_SPRITE_Y] = clip_tex_y;
1068
1069 /* Lower Right */
1070 tile->vtexture[1][RETROGLU_SPRITE_X] = clip_tex_x + clip_tex_w;
1071 tile->vtexture[1][RETROGLU_SPRITE_Y] = clip_tex_y;
1072
1073 /* Upper Right */
1074 tile->vtexture[2][RETROGLU_SPRITE_X] = clip_tex_x + clip_tex_w;
1075 tile->vtexture[2][RETROGLU_SPRITE_Y] = clip_tex_y + clip_tex_h;
1076
1077 /* Upper Right */
1078 tile->vtexture[3][RETROGLU_SPRITE_X] = clip_tex_x + clip_tex_w;
1079 tile->vtexture[3][RETROGLU_SPRITE_Y] = clip_tex_y + clip_tex_h;
1080
1081 /* Upper Left */
1082 tile->vtexture[4][RETROGLU_SPRITE_X] = clip_tex_x;
1083 tile->vtexture[4][RETROGLU_SPRITE_Y] = clip_tex_y + clip_tex_h;
1084
1085 /* Lower Left */
1086 tile->vtexture[5][RETROGLU_SPRITE_X] = clip_tex_x;
1087 tile->vtexture[5][RETROGLU_SPRITE_Y] = clip_tex_y;
1088}
1089
1090void retroglu_init_tile_vertices( struct RETROGLU_TILE* tile ) {
1091
1092 /* == Front Face Vertices == */
1093
1094 /* Lower-Left */
1095 tile->vertices[0][RETROGLU_SPRITE_X] = -1;
1096 tile->vertices[0][RETROGLU_SPRITE_Y] = -1;
1097
1098 /* Lower-Right */
1099 tile->vertices[1][RETROGLU_SPRITE_X] = 1;
1100 tile->vertices[1][RETROGLU_SPRITE_Y] = -1;
1101
1102 /* Upper-Right */
1103 tile->vertices[2][RETROGLU_SPRITE_X] = 1;
1104 tile->vertices[2][RETROGLU_SPRITE_Y] = 1;
1105
1106 /* Upper-Right */
1107 tile->vertices[3][RETROGLU_SPRITE_X] = 1;
1108 tile->vertices[3][RETROGLU_SPRITE_Y] = 1;
1109
1110 /* Upper-Left */
1111 tile->vertices[4][RETROGLU_SPRITE_X] = -1;
1112 tile->vertices[4][RETROGLU_SPRITE_Y] = 1;
1113
1114 /* Lower-Left */
1115 tile->vertices[5][RETROGLU_SPRITE_X] = -1;
1116 tile->vertices[5][RETROGLU_SPRITE_Y] = -1;
1117}
1118
1119void retroglu_set_sprite_clip(
1120 struct RETROGLU_SPRITE* sprite,
1121 uint32_t front_px, uint32_t front_py, uint32_t back_px, uint32_t back_py,
1122 uint32_t pw, uint32_t ph, uint8_t flags
1123) {
1124 /* Set vertices in terms of half the clip size so that rotation is around
1125 * the midpoint of the sprite, not the side!
1126 */
1127 float clip_tex_fx = 0, /* Front tex X */
1128 clip_tex_fy = 0, /* Front tex Y */
1129 clip_tex_bx = 0, /* Back tex X */
1130 clip_tex_by = 0, /* Back tex Y */
1131 clip_tex_w = 0,
1132 clip_tex_h = 0;
1133
1134 /* Setup texture spritesheet. */
1135
1136 clip_tex_fx = retroglu_tex_px_x_to_f( front_px, sprite );
1137 clip_tex_fy = retroglu_tex_px_y_to_f( front_py, sprite );
1138 clip_tex_bx = retroglu_tex_px_x_to_f( back_px, sprite );
1139 clip_tex_by = retroglu_tex_px_y_to_f( back_py, sprite );
1140 clip_tex_w = retroglu_tex_px_x_to_f( pw, sprite );
1141 clip_tex_h = retroglu_tex_px_y_to_f( ph, sprite );
1142
1143 /* == Front Face Textures == */
1144
1145 /* Lower Left */
1146 sprite->vtexture_front[0][RETROGLU_SPRITE_X] = clip_tex_fx;
1147 sprite->vtexture_front[0][RETROGLU_SPRITE_Y] = clip_tex_fy;
1148
1149 /* Lower Right */
1150 sprite->vtexture_front[1][RETROGLU_SPRITE_X] = clip_tex_fx + clip_tex_w;
1151 sprite->vtexture_front[1][RETROGLU_SPRITE_Y] = clip_tex_fy;
1152
1153 /* Upper Right */
1154 sprite->vtexture_front[2][RETROGLU_SPRITE_X] = clip_tex_fx + clip_tex_w;
1155 sprite->vtexture_front[2][RETROGLU_SPRITE_Y] = clip_tex_fy + clip_tex_h;
1156
1157 /* Upper Right */
1158 sprite->vtexture_front[3][RETROGLU_SPRITE_X] = clip_tex_fx + clip_tex_w;
1159 sprite->vtexture_front[3][RETROGLU_SPRITE_Y] = clip_tex_fy + clip_tex_h;
1160
1161 /* Upper Left */
1162 sprite->vtexture_front[4][RETROGLU_SPRITE_X] = clip_tex_fx;
1163 sprite->vtexture_front[4][RETROGLU_SPRITE_Y] = clip_tex_fy + clip_tex_h;
1164
1165 /* Lower Left */
1166 sprite->vtexture_front[5][RETROGLU_SPRITE_X] = clip_tex_fx;
1167 sprite->vtexture_front[5][RETROGLU_SPRITE_Y] = clip_tex_fy;
1168
1169 /* == Back face Textures == */
1170
1171 /* Lower Left */
1172 sprite->vtexture_back[0][RETROGLU_SPRITE_X] = clip_tex_bx;
1173 sprite->vtexture_back[0][RETROGLU_SPRITE_Y] = clip_tex_by;
1174
1175 /* Lower Right */
1176 sprite->vtexture_back[1][RETROGLU_SPRITE_X] = clip_tex_bx + clip_tex_w;
1177 sprite->vtexture_back[1][RETROGLU_SPRITE_Y] = clip_tex_by;
1178
1179 /* Upper Right */
1180 sprite->vtexture_back[2][RETROGLU_SPRITE_X] = clip_tex_bx + clip_tex_w;
1181 sprite->vtexture_back[2][RETROGLU_SPRITE_Y] = clip_tex_by + clip_tex_h;
1182
1183 /* Upper Right */
1184 sprite->vtexture_back[3][RETROGLU_SPRITE_X] = clip_tex_bx + clip_tex_w;
1185 sprite->vtexture_back[3][RETROGLU_SPRITE_Y] = clip_tex_by + clip_tex_h;
1186
1187 /* Upper Left */
1188 sprite->vtexture_back[4][RETROGLU_SPRITE_X] = clip_tex_bx;
1189 sprite->vtexture_back[4][RETROGLU_SPRITE_Y] = clip_tex_by + clip_tex_h;
1190
1191 /* Lower Left */
1192 sprite->vtexture_back[5][RETROGLU_SPRITE_X] = clip_tex_bx;
1193 sprite->vtexture_back[5][RETROGLU_SPRITE_Y] = clip_tex_by;
1194}
1195
1196/* === */
1197
1198void retroglu_init_sprite_vertices( struct RETROGLU_SPRITE* sprite ) {
1199 retroglu_init_sprite_vertices_scale( sprite, 1.0f );
1200}
1201
1202/* === */
1203
1204void retroglu_init_sprite_vertices_scale(
1205 struct RETROGLU_SPRITE* sprite, float scale
1206) {
1207
1208 /* == Front Face Vertices == */
1209
1210 /* Lower-Left */
1211 sprite->vertices_front[0][RETROGLU_SPRITE_X] = -1.0f * scale;
1212 sprite->vertices_front[0][RETROGLU_SPRITE_Y] = -1.0f * scale;
1213
1214 /* Lower-Right */
1215 sprite->vertices_front[1][RETROGLU_SPRITE_X] = scale;
1216 sprite->vertices_front[1][RETROGLU_SPRITE_Y] = -1.0f * scale;
1217
1218 /* Upper-Right */
1219 sprite->vertices_front[2][RETROGLU_SPRITE_X] = scale;
1220 sprite->vertices_front[2][RETROGLU_SPRITE_Y] = scale;
1221
1222 /* Upper-Right */
1223 sprite->vertices_front[3][RETROGLU_SPRITE_X] = scale;
1224 sprite->vertices_front[3][RETROGLU_SPRITE_Y] = scale;
1225
1226 /* Upper-Left */
1227 sprite->vertices_front[4][RETROGLU_SPRITE_X] = -1.0f * scale;
1228 sprite->vertices_front[4][RETROGLU_SPRITE_Y] = scale;
1229
1230 /* Lower-Left */
1231 sprite->vertices_front[5][RETROGLU_SPRITE_X] = -1.0f * scale;
1232 sprite->vertices_front[5][RETROGLU_SPRITE_Y] = -1.0f * scale;
1233
1234 /* == Back Face Vertices == */
1235
1236 /* Lower-Right */
1237 sprite->vertices_back[0][RETROGLU_SPRITE_X] = scale;
1238 sprite->vertices_back[0][RETROGLU_SPRITE_Y] = -1.0f * scale;
1239
1240 /* Lower-Left */
1241 sprite->vertices_back[1][RETROGLU_SPRITE_X] = -1.0f * scale;
1242 sprite->vertices_back[1][RETROGLU_SPRITE_Y] = -1.0f * scale;
1243
1244 /* Upper-Left */
1245 sprite->vertices_back[2][RETROGLU_SPRITE_X] = -1.0f * scale;
1246 sprite->vertices_back[2][RETROGLU_SPRITE_Y] = scale;
1247
1248 /* Upper-Left */
1249 sprite->vertices_back[3][RETROGLU_SPRITE_X] = -1.0f * scale;
1250 sprite->vertices_back[3][RETROGLU_SPRITE_Y] = scale;
1251
1252 /* Upper-Right */
1253 sprite->vertices_back[4][RETROGLU_SPRITE_X] = scale;
1254 sprite->vertices_back[4][RETROGLU_SPRITE_Y] = scale;
1255
1256 /* Lower-Right */
1257 sprite->vertices_back[5][RETROGLU_SPRITE_X] = scale;
1258 sprite->vertices_back[5][RETROGLU_SPRITE_Y] = -1.0f * scale;
1259}
1260
1261/* === */
1262
1263void retroglu_set_sprite_pos(
1264 struct RETROGLU_SPRITE* sprite, uint32_t px, uint32_t py
1265) {
1266 sprite->translate_x = retroglu_scr_px_x_to_f( px );
1267 sprite->translate_y = retroglu_scr_px_y_to_f( py );
1268}
1269
1270/* === */
1271
1272void retroglu_tsrot_sprite( struct RETROGLU_SPRITE* sprite ) {
1273 /* Set the matrix to translate/rotate/scale based on sprite props. */
1274 glTranslatef( sprite->translate_x, sprite->translate_y, 0 );
1275 glRotatef( sprite->rotate_y, 0.0f, 1.0f, 0.0f );
1276}
1277
1278/* === */
1279
1280void retroglu_draw_sprite( struct RETROGLU_SPRITE* sprite ) {
1281 int i = 0;
1282#ifndef RETROGLU_NO_TEXTURES
1283# ifdef RETROGLU_NO_TEXTURE_LISTS
1284 MERROR_RETVAL retval = MERROR_OK;
1285# endif /* RETROGLU_NO_TEXTURES */
1286
1287 glColor3fv( sprite->color );
1288
1289# ifndef RETROGLU_NO_TEXTURE_LISTS
1290 glBindTexture( GL_TEXTURE_2D, sprite->texture.tex.id );
1291# else
1292 maug_mlock( sprite->texture.tex.bytes_h, sprite->texture.tex.bytes );
1293 maug_cleanup_if_null_alloc( uint8_t*, sprite->texture.tex.bytes );
1294 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
1295 sprite->texture.tex.w, sprite->texture.tex.h, 0,
1296 GL_RGBA, GL_UNSIGNED_BYTE,
1297 sprite->texture.tex.bytes );
1298# endif /* !RETROGLU_NO_TEXTURE_LISTS */
1299 glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1300 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1301 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1302
1303 glBegin( GL_TRIANGLES );
1304
1305 for( i = 0 ; 6 > i ; i++ ) {
1306 glTexCoord2fv( sprite->vtexture_front[i] );
1307 glVertex2fv( sprite->vertices_front[i] );
1308 }
1309
1310 for( i = 0 ; 6 > i ; i++ ) {
1311 glTexCoord2fv( sprite->vtexture_back[i] );
1312 glVertex2fv( sprite->vertices_back[i] );
1313 }
1314
1315 glEnd();
1316
1317# ifndef RETROGLU_NO_TEXTURE_LISTS
1318 glBindTexture( GL_TEXTURE_2D, 0 );
1319# else
1320cleanup:
1321 if( NULL != sprite->texture.tex.bytes ) {
1322 maug_munlock( sprite->texture.tex.bytes_h, sprite->texture.tex.bytes );
1323 }
1324# endif /* !RETROGLU_NO_TEXTURE_LISTS */
1325#endif /* !RETROGLU_NO_TEXTURES */
1326}
1327
1328/* === */
1329
1331 struct RETROGLU_SPRITE* sprite, int list_idx,
1332 uint32_t front_px, uint32_t front_py, uint32_t back_px, uint32_t back_py,
1333 uint32_t pw, uint32_t ph, uint8_t flags
1334) {
1335#ifdef RETROGLU_NO_LISTS
1336 sprite->parms[list_idx].front_px = front_px;
1337 sprite->parms[list_idx].front_py = front_py;
1338 sprite->parms[list_idx].back_px = back_px;
1339 sprite->parms[list_idx].back_py = back_py;
1340 sprite->parms[list_idx].pw = pw;
1341 sprite->parms[list_idx].ph = ph;
1342 sprite->parms[list_idx].flags = flags;
1343#else
1344 /* Prerender the sprite to a GL list to call later. */
1345 sprite->lists[list_idx] = glGenLists( 1 );
1346 retroglu_set_sprite_clip(
1347 sprite, front_px, front_py, back_px, back_py, pw, ph, flags );
1348 glNewList( sprite->lists[list_idx], GL_COMPILE );
1349 retroglu_draw_sprite( sprite );
1350 glEndList();
1351#endif /* RETROGLU_NO_LISTS */
1352}
1353
1354/* === */
1355
1356void retroglu_jitrender_sprite( struct RETROGLU_SPRITE* sprite, int list_idx ) {
1357#ifdef RETROGLU_NO_LISTS
1358 /* Prerender the sprite to a GL list to call later. */
1359 retroglu_set_sprite_clip(
1360 sprite,
1361 sprite->parms[list_idx].front_px,
1362 sprite->parms[list_idx].front_py,
1363 sprite->parms[list_idx].back_px,
1364 sprite->parms[list_idx].back_py,
1365 sprite->parms[list_idx].pw,
1366 sprite->parms[list_idx].ph,
1367 sprite->parms[list_idx].flags );
1368 retroglu_draw_sprite( sprite );
1369#else
1370 glCallList( sprite->lists[list_idx] );
1371#endif /* RETROGLU_NO_LISTS */
1372}
1373
1374/* === */
1375
1376void retroglu_free_sprite( struct RETROGLU_SPRITE* sprite ) {
1377#ifndef RETROGLU_NO_TEXTURES
1378 if( NULL != sprite->texture.tex.bytes_h ) {
1379 if( NULL != sprite->texture.tex.bytes ) {
1380 maug_munlock( sprite->texture.tex.bytes_h, sprite->texture.tex.bytes );
1381 }
1382
1383 maug_mfree( sprite->texture.tex.bytes_h );
1384 }
1385
1386# ifndef RETROGLU_NO_TEXTURE_LISTS
1387 if( 0 < sprite->texture.tex.id ) {
1388 glDeleteTextures( 1, (GLuint*)&(sprite->texture.tex.id) );
1389 }
1390# endif /* !RETROGLU_NO_TEXTURE_LISTS */
1391#endif /* !RETROGLU_NO_TEXTURES */
1392}
1393
1394/* === */
1395
1396#ifndef RETROFLAT_NO_STRING
1397
1398# include "mfont8x8.h"
1399
1400static
1401uint32_t g_retroglu_font_tex[RETROSOFT_SETS_COUNT][RETROSOFT_GLYPHS_COUNT];
1402
1403MERROR_RETVAL retroglu_load_glyph( size_t set_idx, size_t glyph_idx ) {
1404 MERROR_RETVAL retval = MERROR_OK;
1405
1406#ifndef RETROGLU_NO_TEXTURES
1407
1408 uint8_t* bmp_px = NULL;
1409 int16_t i = 0,
1410 x = 0,
1411 y = 0;
1412 const char* glyph_dots = gc_font8x8[set_idx][glyph_idx];
1413
1414 /* Allocate temporary buffer for drawing. */
1415 bmp_px = calloc( RETROSOFT_GLYPH_W_SZ * RETROSOFT_GLYPH_H_SZ, 4 );
1416 maug_cleanup_if_null_alloc( uint8_t*, bmp_px );
1417 assert( NULL != bmp_px );
1418
1419 /* Draw font to texture. */
1420 for( y = 0 ; RETROSOFT_GLYPH_H_SZ > y ; y++ ) {
1421 for( x = 0 ; RETROSOFT_GLYPH_W_SZ > x ; x++ ) {
1422 i = ((RETROSOFT_GLYPH_H_SZ - y - 1) * RETROSOFT_GLYPH_W_SZ) + x;
1423 assert( i < RETROSOFT_GLYPH_W_SZ * RETROSOFT_GLYPH_H_SZ * 4 );
1424
1425 if( 1 == ((glyph_dots[y] >> x) & 0x01) ) {
1426 bmp_px[i * 4] = 0xff;
1427 bmp_px[(i * 4) + 1] = 0xff;
1428 bmp_px[(i * 4) + 2] = 0xff;
1429 bmp_px[(i * 4) + 3] = 0xff;
1430 }
1431 }
1432 }
1433
1434# ifndef RETROGLU_NO_TEXTURE_LISTS
1435 assert( 0 == g_retroglu_font_tex[set_idx][glyph_idx] );
1436 glGenTextures( 1, (GLuint*)&(g_retroglu_font_tex[set_idx][glyph_idx]) );
1437 assert( 0 < g_retroglu_font_tex[set_idx][glyph_idx] );
1438 glBindTexture( GL_TEXTURE_2D, g_retroglu_font_tex[set_idx][glyph_idx] );
1439# endif /* !RETROGLU_NO_TEXTURE_LISTS */
1440 /* glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ); */
1441 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
1442 RETROSOFT_GLYPH_W_SZ, RETROSOFT_GLYPH_H_SZ, 0,
1443 GL_RGBA, GL_UNSIGNED_BYTE, bmp_px );
1444
1445cleanup:
1446
1447 if( NULL != bmp_px ) {
1448 free( bmp_px );
1449 }
1450
1451#endif /* RETROGLU_NO_TEXTURES */
1452
1453 return retval;
1454}
1455
1456/* === */
1457
1458MERROR_RETVAL retroglu_init_glyph_tex() {
1459 MERROR_RETVAL retval = MERROR_OK;
1460
1461#ifndef RETROGLU_NO_TEXTURES
1462 size_t i = 0,
1463 j = 0;
1464
1465 /* Only precache textures we we support glBindTexture(). Otherwise, we'll
1466 * have to forcibly load them as we use them later on. */
1467
1468 debug_printf( RETROGLU_TRACE_LVL, "loading glyph textures..." );
1469
1470 for( i = 0 ; RETROSOFT_SETS_COUNT > i ; i++ ) {
1471 for( j = 0 ; RETROSOFT_GLYPHS_COUNT > j ; j++ ) {
1472 retval = retroglu_load_glyph( i, j );
1473 maug_cleanup_if_not_ok();
1474 }
1475 }
1476#endif /* !RETROGLU_NO_TEXTURES */
1477
1478cleanup:
1479
1480 /* TODO: Destroy loaded textures if failure. */
1481
1482 return retval;
1483}
1484
1485/* === */
1486
1487void retroglu_destroy_glyph_tex() {
1488
1489#ifndef RETROGLU_NO_TEXTURE_LISTS
1490 size_t i = 0,
1491 j = 0;
1492
1493 debug_printf( RETROGLU_TRACE_LVL, "destroying glyph textures..." );
1494
1495 for( i = 0 ; RETROSOFT_SETS_COUNT > i ; i++ ) {
1496 for( j = 0 ; RETROSOFT_GLYPHS_COUNT > j ; j++ ) {
1497 glDeleteTextures( 1, (GLuint*)&(g_retroglu_font_tex[i][j]) );
1498 }
1499 }
1500#endif /* !RETROGLU_NO_TEXTURE_LISTS */
1501
1502}
1503
1504/* === */
1505
1506#define RETROGLU_FONT_W 0.05f
1507
1508void retroglu_string(
1509 float x, float y, float z, const RETROGLU_COLOR color,
1510 const char* str, size_t str_sz, const char* font_str, uint8_t flags
1511) {
1512#ifndef RETROGLU_NO_TEXTURES
1513 size_t i = 0;
1514# ifdef RETROGLU_NO_TEXTURE_LISTS
1515 MERROR_RETVAL retval = MERROR_OK;
1516# endif /* RETROGLU_NO_TEXTURE_LISTS */
1517
1518 if( str_sz == 0 ) {
1519 str_sz = maug_strlen( str );
1520 }
1521
1522 for( i = 0 ; str_sz > i ; i++ ) {
1523 /* Stop drawing on NULL. */
1524 if( '\0' == str[i] ) {
1525 break;
1526 }
1527
1528 glColor3fv( color );
1529
1530#ifdef RETROGLU_NO_TEXTURE_LISTS
1531 retval = retroglu_load_glyph( 0, str[i] - ' ' );
1532 maug_cleanup_if_not_ok();
1533#else
1534 glBindTexture( GL_TEXTURE_2D, g_retroglu_font_tex[0][str[i] - ' '] );
1535#endif /* RETROGLU_NO_TEXTURE_LISTS */
1536 glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1537 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1538 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1539
1540 glBegin( GL_TRIANGLES );
1541
1542 glTexCoord2f( 0, 0 );
1543 glVertex3f( x + (RETROGLU_FONT_W * i), y, z );
1544 glTexCoord2f( 1, 0 );
1545 glVertex3f( x + (RETROGLU_FONT_W * i) + RETROGLU_FONT_W, y, z );
1546 glTexCoord2f( 1, 1 );
1547 glVertex3f(
1548 x + (RETROGLU_FONT_W * i) + RETROGLU_FONT_W,
1549 y + RETROGLU_FONT_W, z );
1550
1551 glTexCoord2f( 1, 1 );
1552 glVertex3f(
1553 x + (RETROGLU_FONT_W * i) + RETROGLU_FONT_W,
1554 y + RETROGLU_FONT_W, z );
1555 glTexCoord2f( 0, 1 );
1556 glVertex3f( x + (RETROGLU_FONT_W * i), y + RETROGLU_FONT_W, z );
1557 glTexCoord2f( 0, 0 );
1558 glVertex3f( x + (RETROGLU_FONT_W * i), y, z );
1559
1560 glEnd();
1561
1562# ifdef RETROGLU_NO_TEXTURE_LISTS
1563 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
1564 0, 0, 0,
1565 GL_RGBA, GL_UNSIGNED_BYTE, NULL );
1566# else
1567 glBindTexture( GL_TEXTURE_2D, 0 );
1568# endif /* !RETROGLU_NO_TEXTURE_LISTS */
1569 }
1570
1571# ifdef RETROGLU_NO_TEXTURE_LISTS
1572cleanup:
1573 return;
1574# endif /* RETROGLU_NO_TEXTURE_LISTS */
1575#endif /* !RETROGLU_NO_TEXTURES */
1576}
1577
1578#endif /* !RETROFLAT_NO_STRING */
1579
1580/* === */
1581
1582MERROR_RETVAL retroglu_check_errors( const char* desc ) {
1583 MERROR_RETVAL retval = MERROR_OK;
1584#ifndef RETROGLU_NO_ERRORS
1585 GLenum gl_retval;
1586
1587 do {
1588 gl_retval = glGetError();
1589 if( GL_NO_ERROR != gl_retval ) {
1590 error_printf( "GL error on %s: 0x%x", desc, gl_retval );
1591 retval = MERROR_GUI;
1592 }
1593 } while( GL_NO_ERROR != gl_retval );
1594#endif /* !RETROGLU_NO_ERRORS */
1595
1596 return retval;
1597}
1598
1599/* === */
1600
1601MERROR_RETVAL retroglu_draw_lock( struct RETROFLAT_BITMAP* bmp ) {
1602 MERROR_RETVAL retval = RETROFLAT_OK;
1603
1604 /* TODO: Move this to a common OpenGL header. */
1605
1606 if(
1607 NULL != bmp &&
1608 &(g_retroflat_state->buffer) != bmp &&
1609 (MAUG_MHANDLE)NULL != bmp->tex.bytes_h
1610 ) {
1611 bmp->flags |= RETROFLAT_FLAGS_LOCK;
1612 maug_mlock( bmp->tex.bytes_h, bmp->tex.bytes );
1613 }
1614
1615 return retval;
1616}
1617
1618/* === */
1619
1620MERROR_RETVAL retroglu_draw_release( struct RETROFLAT_BITMAP* bmp ) {
1621 MERROR_RETVAL retval = MERROR_OK;
1622
1623 /* TODO: Move this to a common OpenGL header. */
1624
1625 if( NULL == bmp || &(g_retroflat_state->buffer) == bmp ) {
1626 /* Flush GL buffer and swap screen buffers. */
1627 glFlush();
1628
1629# if defined( RETROFLAT_API_SDL1 )
1630 SDL_GL_SwapBuffers();
1631# elif defined( RETROFLAT_API_SDL2 )
1632 SDL_GL_SwapWindow( g_retroflat_state->platform.window );
1633# elif defined( RETROFLAT_API_WIN16 ) || defined( RETROFLAT_API_WIN32 )
1634 SwapBuffers( g_retroflat_state->platform.hdc_win );
1635# elif defined( RETROFLAT_API_GLUT )
1636 glutSwapBuffers();
1637# endif
1638 } else if( retroflat_bitmap_locked( bmp ) ) {
1639#ifndef RETROGLU_NO_TEXTURES
1640 bmp->flags &= ~RETROFLAT_FLAGS_LOCK;
1641# ifndef RETROGLU_NO_TEXTURE_LISTS
1642 assert( 0 < bmp->tex.id );
1643 assert( NULL != bmp->tex.bytes );
1644
1645 /* Update stored texture if it exists. */
1646 glBindTexture( GL_TEXTURE_2D, bmp->tex.id );
1647 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, bmp->tex.w, bmp->tex.h, 0,
1648 GL_RGBA, GL_UNSIGNED_BYTE, bmp->tex.bytes );
1649 glBindTexture( GL_TEXTURE_2D, 0 );
1650# endif /* !RETROGLU_NO_TEXTURE_LISTS */
1651
1652 /* Unlock texture bitmap. */
1653 maug_munlock( bmp->tex.bytes_h, bmp->tex.bytes );
1654#endif /* !RETROGLU_NO_TEXTURES */
1655 }
1656
1657 return retval;
1658}
1659
1660/* === */
1661
1662MERROR_RETVAL retroglu_load_bitmap(
1663 const char* filename_path, struct RETROFLAT_BITMAP* bmp_out, uint8_t flags
1664) {
1665 MERROR_RETVAL retval = MERROR_OK;
1666#ifndef RETROGLU_NO_TEXTURES
1667 mfile_t bmp_file;
1668 struct MFMT_STRUCT_BMPFILE header_bmp;
1669 MAUG_MHANDLE bmp_palette_h = (MAUG_MHANDLE)NULL;
1670 uint32_t bmp_color = 0;
1671 uint32_t* bmp_palette = NULL;
1672 MAUG_MHANDLE bmp_px_h = (MAUG_MHANDLE)NULL;
1673 uint8_t* bmp_px = NULL;
1674 off_t bmp_px_sz = 0;
1675 uint8_t bmp_r = 0,
1676 bmp_g = 0,
1677 bmp_b = 0,
1678 bmp_color_idx = 0,
1679 bmp_flags = 0;
1680 off_t i = 0;
1681
1682 retval = mfile_open_read( filename_path, &bmp_file );
1683 maug_cleanup_if_not_ok();
1684
1685 /* TODO: mfmt file detection system. */
1686 header_bmp.magic[0] = 'B';
1687 header_bmp.magic[1] = 'M';
1688 header_bmp.info.sz = 40;
1689
1690 retval = mfmt_read_bmp_header(
1691 (struct MFMT_STRUCT*)&header_bmp,
1692 &bmp_file, 0, mfile_get_sz( &bmp_file ), &bmp_flags );
1693 maug_cleanup_if_not_ok();
1694
1695 assert( 0 < mfile_get_sz( &bmp_file ) );
1696
1697 /* Setup bitmap options from header. */
1698 bmp_out->tex.w = header_bmp.info.width;
1699 bmp_out->tex.h = header_bmp.info.height;
1700 bmp_out->tex.sz = bmp_out->tex.w * bmp_out->tex.h * 4;
1701 bmp_out->tex.bpp = 24;
1702
1703 /* Allocate a space for the bitmap palette. */
1704 bmp_palette_h = maug_malloc( 4, header_bmp.info.palette_ncolors );
1705 maug_cleanup_if_null_alloc( MAUG_MHANDLE, bmp_palette_h );
1706
1707 maug_mlock( bmp_palette_h, bmp_palette );
1708 maug_cleanup_if_null_alloc( uint32_t*, bmp_palette );
1709
1710 retval = mfmt_read_bmp_palette(
1711 (struct MFMT_STRUCT*)&header_bmp,
1712 bmp_palette, 4 * header_bmp.info.palette_ncolors,
1713 &bmp_file, 54 /* TODO */, mfile_get_sz( &bmp_file ) - 54, bmp_flags );
1714 maug_cleanup_if_not_ok();
1715
1716 /* Allocate a space for the bitmap pixels. */
1717 bmp_px_sz = header_bmp.info.width * header_bmp.info.height;
1718 bmp_px_h = maug_malloc( 1, bmp_px_sz );
1719 maug_cleanup_if_null_alloc( MAUG_MHANDLE, bmp_px_h );
1720
1721 maug_mlock( bmp_px_h, bmp_px );
1722 maug_cleanup_if_null_alloc( uint8_t*, bmp_px );
1723
1724 retval = mfmt_read_bmp_px(
1725 (struct MFMT_STRUCT*)&header_bmp,
1726 bmp_px, bmp_px_sz,
1727 &bmp_file, header_bmp.px_offset,
1728 mfile_get_sz( &bmp_file ) - header_bmp.px_offset, bmp_flags );
1729 maug_cleanup_if_not_ok();
1730
1731 /* Allocate buffer for unpacking. */
1732 debug_printf( 0, "creating bitmap: " SIZE_T_FMT " x " SIZE_T_FMT,
1733 bmp_out->tex.w, bmp_out->tex.h );
1734 bmp_out->tex.bytes_h = maug_malloc( bmp_out->tex.w * bmp_out->tex.h, 4 );
1735 maug_cleanup_if_null_alloc( MAUG_MHANDLE, bmp_out->tex.bytes_h );
1736
1737 maug_mlock( bmp_out->tex.bytes_h, bmp_out->tex.bytes );
1738 maug_cleanup_if_null_alloc( uint8_t*, bmp_out->tex.bytes );
1739
1740 /* Unpack palletized bitmap into BGRA with color key. */
1741 for( i = 0 ; bmp_px_sz > i ; i++ ) {
1742 if( bmp_px_sz - i - 1 > bmp_px_sz ) {
1743 error_printf(
1744 "pixel overflow! (" OFF_T_FMT " of " OFF_T_FMT " bytes!)",
1745 bmp_px_sz - i - 1, bmp_px_sz );
1746 retval = MERROR_OVERFLOW;
1747 goto cleanup;
1748 }
1749
1750 /* Grab the color from the palette by index. */
1751 bmp_color_idx = bmp_px[bmp_px_sz - i - 1]; /* Reverse image. */
1752 if( bmp_color_idx >= header_bmp.info.palette_ncolors ) {
1753 error_printf(
1754 "invalid color at px " OFF_T_FMT ": %02x",
1755 bmp_px_sz - i - 1, bmp_color_idx );
1756 continue;
1757 }
1758 bmp_color = bmp_palette[bmp_color_idx];
1759 bmp_r = (bmp_color >> 16) & 0xff;
1760 bmp_g = (bmp_color >> 8) & 0xff;
1761 bmp_b = bmp_color & 0xff;
1762
1763 bmp_out->tex.bytes[i * 4] = bmp_r;
1764 bmp_out->tex.bytes[(i * 4) + 1] = bmp_g;
1765 bmp_out->tex.bytes[(i * 4) + 2] = bmp_b;
1766 if(
1768 RETROFLAT_TXP_R == bmp_r &&
1769 RETROFLAT_TXP_G == bmp_g &&
1770 RETROFLAT_TXP_B == bmp_b
1771 ) {
1772 /* Transparent pixel found. */
1773 bmp_out->tex.bytes[(i * 4) + 3] = 0x00;
1774 } else {
1775 bmp_out->tex.bytes[(i * 4) + 3] = 0xff;
1776 }
1777 }
1778
1779# ifndef RETROGLU_NO_TEXTURE_LISTS
1780 glGenTextures( 1, (GLuint*)&(bmp_out->tex.id) );
1781 glBindTexture( GL_TEXTURE_2D, bmp_out->tex.id );
1782 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, bmp_out->tex.w, bmp_out->tex.h, 0,
1783 GL_RGBA, GL_UNSIGNED_BYTE, bmp_out->tex.bytes );
1784 glBindTexture( GL_TEXTURE_2D, 0 );
1785# endif /* !RETROGLU_NO_TEXTURE_LISTS */
1786
1787cleanup:
1788
1789 if( NULL != bmp_out->tex.bytes ) {
1790 maug_munlock( bmp_out->tex.bytes_h, bmp_out->tex.bytes );
1791 }
1792
1793 if( NULL != bmp_px ) {
1794 maug_munlock( bmp_px_h, bmp_px );
1795 }
1796
1797 if( NULL != bmp_px_h ) {
1798 maug_mfree( bmp_px_h );
1799 }
1800
1801 if( NULL != bmp_palette ) {
1802 maug_munlock( bmp_palette_h, bmp_palette );
1803 }
1804
1805 if( NULL != bmp_palette_h ) {
1806 maug_mfree( bmp_palette_h );
1807 }
1808
1809 mfile_close( &bmp_file );
1810
1811#endif /* !RETROGLU_NO_TEXTURES */
1812
1813 return retval;
1814}
1815
1816/* === */
1817
1818MERROR_RETVAL retroglu_create_bitmap(
1819 size_t w, size_t h, struct RETROFLAT_BITMAP* bmp_out, uint8_t flags
1820) {
1821 MERROR_RETVAL retval = MERROR_OK;
1822
1823#ifdef RETROGLU_NO_TEXTURES
1824 error_printf( "textures not enabled!" );
1825 retval = MERROR_GUI;
1826#else
1827
1828 if( w > 256 ) {
1829 error_printf( "warning! attempting to create texture with w > 256 ("
1830 SIZE_T_FMT "). This may not work on Win32!", w );
1831 }
1832
1833 if( h > 256 ) {
1834 error_printf( "warning! attempting to create texture with h > 256 ("
1835 SIZE_T_FMT "). This may not work on Win32!", h );
1836 }
1837
1838 bmp_out->tex.w = w;
1839 bmp_out->tex.h = h;
1840 /* TODO: Overflow checking. */
1841 debug_printf( 0, "creating bitmap: " SIZE_T_FMT " x " SIZE_T_FMT,
1842 bmp_out->tex.w, bmp_out->tex.h );
1843 bmp_out->tex.bytes_h =
1844 maug_malloc( bmp_out->tex.w * bmp_out->tex.h, 4 );
1845 maug_cleanup_if_null_alloc( MAUG_MHANDLE, bmp_out->tex.bytes_h );
1846
1847 maug_mlock( bmp_out->tex.bytes_h, bmp_out->tex.bytes );
1848 maug_cleanup_if_null_lock( uint8_t*, bmp_out->tex.bytes );
1849
1850 /* TODO: Overflow checking. */
1851 maug_mzero(
1852 bmp_out->tex.bytes,
1853 bmp_out->tex.w * bmp_out->tex.h * sizeof( uint32_t ) );
1854
1855# ifndef RETROGLU_NO_TEXTURE_LISTS
1856 glGenTextures( 1, (GLuint*)&(bmp_out->tex.id) );
1857 debug_printf( RETROFLAT_BITMAP_TRACE_LVL,
1858 "assigned bitmap texture: " UPRINTF_U32_FMT, bmp_out->tex.id );
1859 retval = retroglu_check_errors( "gentextures" );
1860 maug_cleanup_if_not_ok();
1861# endif /* !RETROGLU_NO_TEXTURE_LISTS */
1862
1863cleanup:
1864 if( NULL != bmp_out->tex.bytes ) {
1865 maug_munlock( bmp_out->tex.bytes_h, bmp_out->tex.bytes );
1866 }
1867
1868#endif /* !RETROGLU_NO_TEXTURES */
1869
1870 return retval;
1871}
1872
1873/* === */
1874
1875void retroglu_destroy_bitmap( struct RETROFLAT_BITMAP* bmp ) {
1876#ifndef RETROGLU_NO_TEXTURES
1877 debug_printf( 1, "destroying bitmap..." );
1878
1879 if( NULL != bmp->tex.bytes ) {
1880 maug_munlock( bmp->tex.bytes_h, bmp->tex.bytes );
1881 }
1882
1883 if( NULL != bmp->tex.bytes_h ) {
1884 maug_mfree( bmp->tex.bytes_h );
1885 }
1886
1887# ifndef RETROGLU_NO_TEXTURE_LISTS
1888 if( 0 < bmp->tex.id ) {
1889 debug_printf( 0,
1890 "destroying bitmap texture: " UPRINTF_U32_FMT, bmp->tex.id );
1891 glDeleteTextures( 1, (GLuint*)&(bmp->tex.id) );
1892 }
1893# endif /* !RETROGLU_NO_TEXTURE_LISTS */
1894#endif /* !RETROGLU_NO_TEXTURES */
1895}
1896
1897/* === */
1898
1899MERROR_RETVAL retroglu_blit_bitmap(
1900 struct RETROFLAT_BITMAP* target, struct RETROFLAT_BITMAP* src,
1901 size_t s_x, size_t s_y, size_t d_x, size_t d_y, size_t w, size_t h,
1902 int16_t instance
1903) {
1904 MERROR_RETVAL retval = MERROR_OK;
1905 int y_iter = 0;
1906
1907 /* TODO: Check memcpy, etc? */
1908
1909 if( NULL == target || retroflat_screen_buffer() == target ) {
1910 /* TODO: Create ortho sprite on screen. */
1911
1912 } else {
1913 /* Blit to texture. */
1914
1915 assert( NULL != target->tex.bytes );
1916
1917 /* TODO: Some kind of source-autolock? */
1918 assert( !retroflat_bitmap_locked( src ) );
1919 maug_mlock( src->tex.bytes_h, src->tex.bytes );
1920 for( y_iter = 0 ; h > y_iter ; y_iter++ ) {
1921 /* TODO: Handle transparency! */
1922 memcpy(
1923 &(target->tex.bytes[(((y_iter * target->tex.w) + d_x) * 4)]),
1924 &(src->tex.bytes[(((y_iter * src->tex.w) + s_x) * 4)]),
1925 w * 4 );
1926 }
1927 maug_munlock( src->tex.bytes_h, src->tex.bytes );
1928
1929 }
1930
1931 return retval;
1932}
1933
1934/* === */
1935
1936void retroglu_px(
1937 struct RETROFLAT_BITMAP* target, const RETROFLAT_COLOR color_idx,
1938 size_t x, size_t y, uint8_t flags
1939) {
1940
1941 if(
1942 RETROFLAT_FLAGS_BITMAP_RO ==
1943 (RETROFLAT_FLAGS_BITMAP_RO & target->flags) ||
1944 target->tex.w <= x ||
1945 target->tex.h <= y
1946 ) {
1947 return;
1948 }
1949
1950 assert( NULL != target->tex.bytes );
1951 /* assert( retroflat_bitmap_locked( target ) ); */
1952
1953 /* Draw pixel colors from texture palette. */
1954 target->tex.bytes[(((y * target->tex.w) + x) * 4) + 0] =
1955 g_retroflat_state->tex_palette[color_idx][0];
1956 target->tex.bytes[(((y * target->tex.w) + x) * 4) + 1] =
1957 g_retroflat_state->tex_palette[color_idx][1];
1958 target->tex.bytes[(((y * target->tex.w) + x) * 4) + 2] =
1959 g_retroflat_state->tex_palette[color_idx][2];
1960
1961 /* Set pixel as opaque. */
1962 target->tex.bytes[(((y * target->tex.w) + x) * 4) + 3] = 0xff;
1963}
1964
1965#else
1966
1967# define RETROFLAT_COLOR_TABLE_GL( idx, name_l, name_u, r, g, b, cgac, cgad ) \
1968 extern MAUG_CONST float RETROGLU_COLOR_ ## name_u[];
1969
1970RETROFLAT_COLOR_TABLE( RETROFLAT_COLOR_TABLE_GL )
1971
1972#endif /* RETROGLU_C */
1973
1974 /* maug_retroglu */
1975
1976#endif /* !RETROGLU_H */
1977
int MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19
MERROR_RETVAL mfmt_read_bmp_px(struct MFMT_STRUCT *header, uint8_t SEG_FAR *px, off_t px_sz, mfile_t *p_file_in, uint32_t file_offset, off_t file_sz, uint8_t flags)
Read mfmt_bitmap pixels into an 8-bit memory bitmap.
#define maug_mzero(ptr, sz)
Zero the block of memory pointed to by ptr.
Definition mmem.h:62
MERROR_RETVAL mfile_open_read(const char *filename, mfile_t *p_file)
Open a file and read it into memory or memory-map it.
void mfile_close(mfile_t *p_file)
Close a file opened with mfile_open_read().
#define RETROFLAT_TXP_G
Compiler-define-overridable constant indicating the Green value of the transparency color on platform...
Definition retroflt.h:616
#define RETROFLAT_TXP_B
Compiler-define-overridable constant indicating the Blue value of the transparency color on platforms...
Definition retroflt.h:625
#define RETROFLAT_TXP_R
Compiler-define-overridable constant indicating the Red value of the transparency color on platforms ...
Definition retroflt.h:607
int8_t RETROFLAT_COLOR
Defines an index in the platform-specific color-table.
Definition retroflt.h:307
#define RETROFLAT_COLOR_TABLE(f)
This macro defines all colors supported by RetroFlat for primative operations, particularly using ret...
Definition retroflt.h:288
#define RETROFLAT_PATH_SEP
The valid path separator on the target platform.
Definition retroflt.h:745
#define RETROFLAT_FLAGS_OPAQUE
Flag for retroflat_create_bitmap() to create a bitmap without transparency.
Definition retroflt.h:361
#define RETROFLAT_OK
Certain functions return this when there was no problem.
Definition retroflt.h:327
void retroglu_parse_init(struct RETROGLU_PARSER *parser, struct RETROGLU_OBJ *obj, retroglu_mtl_cb load_mtl, void *load_mtl_data)
Initialize a RETROGLU_PARSER.
#define retroglu_parser_state(parser, new_state)
Change the parser state.
Definition retroglu.h:308
MERROR_RETVAL retroglu_parse_obj_c(struct RETROGLU_PARSER *parser, unsigned char c)
Parse OBJ data into a parser, one character at a time.
int(* retroglu_mtl_cb)(const char *filename, struct RETROGLU_PARSER *parser, void *data)
Callback to execute when its associate in RETROGLU_OBJ_TOKENS is found in an OBJ file.
Definition retroglu.h:335
#define RETROGLU_OBJ_TOKENS(f)
Table of OBJ file tokens understood by the parser.
Definition retroglu.h:316
void retroglu_prerender_sprite(struct RETROGLU_SPRITE *sprite, int list_idx, uint32_t front_px, uint32_t front_py, uint32_t back_px, uint32_t back_py, uint32_t pw, uint32_t ph, uint8_t flags)
If lists are enabled, prerender the sprite to a list using the given params to retroglu_set_sprite_cl...
void retroglu_draw_sprite(struct RETROGLU_SPRITE *sprite)
Draw the given sprite. This function never uses a list, and can therefore be used to create a draw li...
void retroglu_init_sprite_vertices(struct RETROGLU_SPRITE *sprite)
Setup the sprite vertices for the poly the sprite will be drawn on. This should be called once when t...
void retroglu_jitrender_sprite(struct RETROGLU_SPRITE *sprite, int list_idx)
If lists are enabled, render the sprite list at list_idx. Otherwise, draw the sprite using retroglu_d...
#define retroflat_screen_h()
Get the current screen height in pixels.
Definition retpltd.h:38
#define retroflat_screen_buffer()
Get the direct screen buffer or the VDP buffer if a VDP is loaded.
Definition retpltd.h:41
#define retroflat_screen_w()
Get the current screen width in pixels.
Definition retpltd.h:35
Definition mfile.h:74
Definition mfmt.h:111
Generic image description struct.
Definition mfmt.h:62
Platform-specific bitmap structure. retroflat_bitmap_ok() can be used on a pointer to it to determine...
Definition retpltd.h:21
uint8_t flags
Platform-specific bitmap flags.
Definition retpltd.h:25
struct RETROFLAT_BITMAP buffer
Off-screen buffer bitmap.
Definition retroflt.h:1272
Definition retroglu.h:120
uint16_t vertex_idxs[RETROGLU_FACE_VERTICES_SZ_MAX]
List of vertex indices from the associated RETROGLU_PARSER::vertices.
Definition retroglu.h:127
Definition retroglu.h:111
Definition retroglu.h:138
struct RETROGLU_FACE faces[RETROGLU_FACES_SZ_MAX]
List of faces from an OBJ file. Faces comprise a list of polygons denoted by index of the vertices in...
Definition retroglu.h:150
As retroglu_parse_obj_c() parses OBJ data, it populates this struct with object information.
Definition retroglu.h:342
Definition retroglu.h:213
If draw lists are disabled, this struct holds a list of params for retroglu_set_sprite_clip() so that...
Definition retroglu.h:173
Definition retroglu.h:183
Definition retroglu.h:200
Definition retroglu.h:100
Definition retroglu.h:106