/* ogl.c */

/* ogl_draw_string, in its original form for GTK1 using GtkGlArea */

/*
 *  ``The contents of this file are subject to the Mozilla Public License
 *  Version 1.0 (the "License"); you may not use this file except in
 *  compliance with the License. You may obtain a copy of the License at
 *  http://www.mozilla.org/MPL/
 *
 *  Software distributed under the License is distributed on an "AS IS"
 *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 *  License for the specific language governing rights and limitations
 *  under the License.
 *
 *  The Original Code is the "Light Speed!" relativistic simulator.
 *
 *  The Initial Developer of the Original Code is Daniel Richard G.
 *  Portions created by the Initial Developer are Copyright (C) 1999
 *  Daniel Richard G. <skunk@mit.edu> All Rights Reserved.
 *
 *  Contributor(s): ______________________________________.''
 */


#include "lightspeed.h"

/* Draws a string in the viewport
 * Meaning of args can vary, see initial switch statement
 * "size" specifies size of text: 0 (small), 1 (medium) or 2 (large)
 * NOTE: This function requires some pre-existing state; namely, the target
 * GL context must already be made current as well as properly initialized
 * (see ogl_blank( ) or info_display( ) to see what I mean) */
void
ogl_draw_string( const void *data, int message, int size )
{
	static GdkFont **fonts;
	static unsigned int *font_dlist_bases;
	static int *font_heights;
	static int width, height;
	static int fn_big;
	static int num_tl_lines, num_tr_lines, num_bl_lines, num_br_lines;
	static int num_cen_lines;
	const char *test_str = "XXXX XXXX XXXX XXXX";
	camera *cam;
	int pos_code;
	int edge_dx = 1, edge_dy = 1;
	int x = 0, y = 0;
	int fn;
	int i;
	char str_buf[256];
	char *disp_str;
	char *next_disp_str;

	switch (message) {
	case INITIALIZE:
		/* First-time initialization */
		fonts = xmalloc( num_font_sizes * sizeof(GdkFont *) );
		font_dlist_bases = xmalloc( num_font_sizes * sizeof(unsigned int *) );
		font_heights = xmalloc( num_font_sizes * sizeof(int *) );
		for (i = 0; i < num_font_sizes; i++) {
			fonts[i] = gdk_font_load( sys_font_names[i] );
			if (fonts[i] == NULL) {
				printf( "ERROR: Cannot load font: %s\n", sys_font_names[i] );
				fflush( stdout );
				continue;
			}
			font_heights[i] = fonts[i]->ascent + fonts[i]->descent;

			font_dlist_bases[i] = glGenLists( 192 );
			gdk_gl_use_gdk_font( fonts[i], 0, 192, font_dlist_bases[i] );
		}
		return;

	case RESET:
		/* Once-per-GL-redraw initialization */
		cam = (camera *)data;
		/* Get GL widget dimensions */
		width = cam->width;
		height = cam->height;
		/* Reset line counters */
		num_tl_lines = 0;
		num_tr_lines = 0;
		num_bl_lines = 0;
		num_br_lines = 0;
		num_cen_lines = 0;
		/* Determine upper limit on the font sizes we should use */
		for (i = 0; i < num_font_sizes; i++) {
			fn_big = i; /* font number of "big" (size 2) font */
			/* Test string should be minimally 1/3 viewport width */
			if (gdk_string_width( fonts[i], test_str ) > (width / 3))
				break;
		}
		return;

	default:
		pos_code = message;
		disp_str = (char *)data;
		break;
	}

	/* Check string for newlines, and queue if necessary */
	i = strcspn( disp_str, "\n" );
	if (i < strlen( disp_str )) {
		strcpy( str_buf, disp_str );
		str_buf[i] = '\0';
		disp_str = str_buf;
		next_disp_str = &str_buf[i + 1];
	}
	else
		next_disp_str = NULL;

	/* Determine which (proportional) font size to use */
	fn = MIN(fn_big, MAX(0, fn_big - 2 + size)); /* 0 <= fn <= fn_big */

	/* x coord. of base point */
	switch (pos_code) {
	case POS_TOP_LEFT:
	case POS_BOTTOM_LEFT:
		x = width / 100;
		edge_dx = 1;
		break;

	case POS_TOP_RIGHT:
	case POS_BOTTOM_RIGHT:
		x = (width * 99) / 100;
		x -= gdk_string_width( fonts[fn], disp_str );
		edge_dx = -1;
		break;

	case POS_CENTER:
		x = width / 2;
		x -= gdk_string_width( fonts[fn], disp_str ) / 2;
		edge_dx = 0;
		break;

	default:
#ifdef DEBUG
		crash( "ogl_draw_string( ): invalid position code" );
#endif
		return;
	}

	/* y coord. of base point */
	switch (pos_code) {
	case POS_BOTTOM_LEFT:
	case POS_BOTTOM_RIGHT:
		y = height / 100;
		edge_dy = 1;
		break;

	case POS_TOP_LEFT:
	case POS_TOP_RIGHT:
		y = (99 * height) / 100;
		y -= font_heights[fn];
		edge_dy = -1;
		break;

	case POS_CENTER:
		y = height / 2;
		y -= font_heights[fn] / 2;
		edge_dy = -1;
		break;
	}

	/* This makes multi-line readouts possible */
	switch (pos_code) {
	case POS_TOP_LEFT:
		y -= num_tl_lines * font_heights[fn];
		++num_tl_lines;
		break;

	case POS_TOP_RIGHT:
		y -= num_tr_lines * font_heights[fn];
		++num_tr_lines;
		break;

	case POS_BOTTOM_LEFT:
		y += num_bl_lines * font_heights[fn];
		++num_bl_lines;
		break;

	case POS_BOTTOM_RIGHT:
		y += num_br_lines * font_heights[fn];
		++num_br_lines;
		break;

	case POS_CENTER:
		y -= num_cen_lines * font_heights[fn];
		++num_cen_lines;
		break;
	}

	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );
	glOrtho( 0.0, (double)width, 0.0, (double)height, -1.0, 1.0 );
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity( );

	/* Draw text backing */
	glColor3f( INFODISP_TEXT_BACK_R, INFODISP_TEXT_BACK_G, INFODISP_TEXT_BACK_B );
	glRasterPos2i( x + edge_dx, y + edge_dy );
	glListBase( font_dlist_bases[fn] );
	glCallLists( strlen(disp_str), GL_UNSIGNED_BYTE, disp_str );

	/* Draw text face */
	glColor3f( INFODISP_TEXT_FRONT_R, INFODISP_TEXT_FRONT_G, INFODISP_TEXT_FRONT_B );
	glRasterPos2i( x, y );
	glCallLists( strlen(disp_str), GL_UNSIGNED_BYTE, disp_str );

	/* Finally, do next line if disp_str had newlines */
	if (next_disp_str != NULL)
		ogl_draw_string( next_disp_str, pos_code, size );
}
