/* * Copyright 1986, 1987, 1988, 1989, 1990 Ithaca Software, Alameda, CA * */

#include		"hoops.h"

#ifdef	NEW_HIDDEN
#	define		HD_Printf_Driver		HD_New_Printf_Driver
#endif

#ifndef PRINTF

	global boolean HD_Printf_Driver (actor, request)
	   stack				Driver			*actor;
	   stack				int				request; {
	   extern				boolean			HD_No_Driver ();

	   return HD_No_Driver (actor, request, "Printf");
	}

#else

#	include		   "patterns.h"
#	include		   "driver.h"

#	include		   <stdio.h>

#	ifdef PM
#		include		   <string.h>
#	endif

	typedef struct {
		Incarnation		last_line_incarnation,
						last_face_incarnation;
		FILE			*fp;
		boolean			using_stdout;
		int				last_button;
		int				last_keyboard;
		int				last_mouse;
	}	Printf_State;

	local	void			get_actions ();

	global boolean HD_Printf_Driver (actor, request)
		stack		Driver			*actor;
		stack		int				request; {
		extern		boolean			HD_Connect_Standard_Driver();

		return HD_Connect_Standard_Driver (actor, request, ADDR(get_actions));
	}

	local boolean start_device (dc)
		stack		Display_Context			*dc; {
		register	Printf_State			*state;

		ALLOC (state, Printf_State);
		dc->data = (void *) state;

		if (dc->actor_name == '\0' ||
				HI_Equal_Strings (dc->actor_name, "stdout")) {
			state->using_stdout = true;
			state->fp = stdout;
			fprintf (state->fp, "Start_device: stdout\n");
		}		 
		else if (HI_Equal_Strings (dc->actor_name, "null")) {
			state->fp = null;
		}		 
		else {
			state->using_stdout = false;

			if ((state->fp = fopen(dc->actor_name, "w")) == null) {
				HI_Warning (Sprintf_S (null, "Can't open Printf driver output '%s'",
							dc->actor_name));
				FREE (state, Printf_State);
				return false;
			}
			fprintf (state->fp, "Start_device: %s\n", dc->actor_name);
		}

		state->last_button = 0;
		state->last_mouse = 100;
		state->last_keyboard = 0;

		return true;
	}

	local void get_physical_info (dc)
		stack		Display_Context			*dc; {
		register	Printf_State			*state = (Printf_State *) dc->data;

		if (state->fp != null) fprintf (state->fp, "get_physical_info()\n");

		dc->physical.color_system = MAPPED_RGB;
		dc->physical.number_of_colors = 256;
		dc->physical.nominal_color_resolution = 256;

		dc->physical.offset_in_pixels.x = 0;
		dc->physical.offset_in_pixels.y = 0;

		/* make it match the Sonys for now */
		dc->physical.number_of_pixels.x = 1280;
		dc->physical.number_of_pixels.y = 1024;

		dc->physical.size.x = 25.4 * 1280.0/1024.0;
		dc->physical.size.y = 25.4;

		dc->physical.driver_type = "Printf";
		dc->physical.windowing_system = false;
		dc->physical.has_locater = false;
		dc->physical.has_keyboard = false;
		dc->physical.display_type = "debugging printout";

		/* make it a Z buffer for now */
		dc->physical.z_buffer_depth = 16;
		dc->physical.incremental_z_updates = true;
		dc->physical.max_polygon_points = 100; /* for fun */
		dc->physical.max_polyline_points = 100; /* for fun */
	}

	local void stop_device (dc)
		stack		Display_Context			*dc;  {
		register	Printf_State			*state =(Printf_State *) dc->data;

		if (state->fp != null) {
			fprintf (state->fp, "stop_device()\n");

			if (!state->using_stdout) fclose (state->fp);
		}

		FREE (state, Printf_State);
	}

	local void init_picture (dc)
		stack		Display_Context			*dc;  {
		register	Printf_State			*state =(Printf_State *) dc->data;

#		ifdef	NEW_HIDDEN
			if (dc->options.new_hidden_surface) {	
				extern	  void				HD_New_Insert_In_Hidden_Tree(),
											HD_New_See_Whats_Hidden(),
											HD_New_Hide_Polygon();

				dc->actions.insert_in_hidden_tree = ADDR (HD_New_Insert_In_Hidden_Tree);
				dc->actions.see_whats_hidden	  = ADDR (HD_New_See_Whats_Hidden);
				dc->actions.hide_polygon		  = ADDR (HD_New_Hide_Polygon);
			}
			else {
				extern	  void				HD_Insert_In_Hidden_Tree(),
											HD_See_Whats_Hidden(),
											HD_Hide_Polygon();

				dc->actions.insert_in_hidden_tree = ADDR (HD_Insert_In_Hidden_Tree);
				dc->actions.see_whats_hidden	  = ADDR (HD_See_Whats_Hidden);
				dc->actions.hide_polygon		  = ADDR (HD_Hide_Polygon);
			}
#		endif

		if (state->fp != null) fprintf (state->fp, "init_picture()\n");
		state->last_line_incarnation = 0;
		state->last_face_incarnation = 0;
	}

	local void finish_picture (dc, swap_buffers) 
		stack		Display_Context		*dc;  
		stack		boolean				swap_buffers; {
		register	Printf_State		*state =(Printf_State *) dc->data;

		if (state->fp != null) {
			fprintf (state->fp, "finish_picture()\n");
			fflush (state->fp);
		}
	}

	local long get_outer_window (dc)
		register		Display_Context			*dc;  {
		register		Printf_State			*state =(Printf_State *) dc->data;

		if (state->fp != null) 
			fprintf (state->fp, "get_outer_window(%d, %d, %d, %d)\n",
				dc->outer.extent.left,
				dc->outer.extent.right,
				dc->outer.extent.bottom,
				dc->outer.extent.top);
	
		return (long)state->fp;
	}

	local void clear_z_buffer (dc, left, right, bottom, top)
		register		Display_Context			*dc;  
		stack			int						left, right, bottom, top; {
		register		Printf_State			*state =(Printf_State *) dc->data;

		if (state->fp != null) 
			fprintf (state->fp, "clear_z_buffer (%d, %d, %d, %d)\n",
					 left, right, bottom, top);		
	}

	local void free_outer_window (dc)
		stack		Display_Context			*dc;  {
		register	Printf_State			*state =(Printf_State *) dc->data;

		if (state->fp != null) fprintf (state->fp, "free_outer_window()\n");
	}

	local void resize_outer_window (dc)
		register		Display_Context			*dc;  {
		register		Printf_State			*state =(Printf_State *) dc->data;

		if (state->fp != null) 
			fprintf (state->fp, "resize_outer_window(%d, %d, %d, %d)\n",
				dc->outer.extent.left,
				dc->outer.extent.right,
				dc->outer.extent.bottom,
				dc->outer.extent.top);
	}

	local char *color_name (bp, color, dc)
		stack	char			*bp;
		stack	Driver_Color	*color;
		stack	Display_Context *dc; {
		
		switch (dc->physical.color_system) {
			case MAPPED_RGB: sprintf (bp, "index %d", color->map_index); break;
			case DIRECT_RGB: sprintf (bp, "(r=%d, g=%d, b=%d)",
										  (int)color->direct_rgb.r,
										  (int)color->direct_rgb.g,
										  (int)color->direct_rgb.b);	break;
			case GRAY_SCALE: sprintf (bp, "gray level %d", 
										  color->gray_level);			break;
			default:		 sprintf (bp, "** Unknown color system");	break;
		}
		return bp;
	}

	local void new_line_rendition (lr)
		register		Line_Rendition	*lr;  {
		register		Printf_State	*state = (Printf_State *)lr->h.data;

		if (state->fp != null) {
			stack		char			*pattern,
										buf[100];
			switch (lr->pattern) {
				case LP_SOLID:	   pattern = "SOLID";	break;
				case LP_DASHDOT:   pattern = "DASHDOT"; break;
				case LP_DASHED:	   pattern = "DASHED";	break;
				case LP_DOTTED:	   pattern = "DOTTED";	break;
				default:		pattern = "** Unrecognized";	break;
			}

			fprintf (state->fp, 
				"(new line rendition: pattern = %s, weight = %d, color = %s%s)\n",
				pattern, lr->weight,	
				color_name(buf, &lr->color, lr->h.display_context),
				lr->h.transform_rendition->z_buffering ? ", Z buffering" : "");
		}

		state->last_line_incarnation = lr->h.incarnation;
	}

	local void new_face_rendition (fr)
		register		Face_Rendition	*fr;  {
		register		Printf_State	*state = (Printf_State *)fr->h.data;

		if (state->fp != null) {
			stack		char			*pattern,
										buf1[100],
										buf2[100];
			switch (fr->pattern) {
				case FP_SOLID:					pattern = "SOLID";				break;
				case FP_CHECKERBOARD:			pattern = "CHECKERBOARD";		break;
				case FP_CROSSHATCH:				pattern = "CROSSHATCH";			break;
				case FP_DIAMONDS:				pattern = "DIAMONDS";			break;
				case FP_HORIZONTAL_BARS:		pattern = "HORIZONTAL_BARS";	break;
				case FP_SLANT_LEFT:				pattern = "SLANT_LEFT";			break;
				case FP_SLANT_RIGHT:			pattern = "SLANT_RIGHT";		break;
				case FP_SQUARE_DOTS:			pattern = "SQUARE_DOTS";		break;
				case FP_VERTICAL_BARS:			pattern = "VERTICAL_BARS";		break;
				case FP_WINDOW_CHECKERBOARD:	pattern = "WINDOW_CHECKERBOARD";		break;
				case FP_WINDOW_CROSSHATCH:		pattern = "WINDOW_CROSSHATCH";	break;
				case FP_WINDOW_DIAMONDS:		pattern = "WINDOW_DIAMONDS";	break;
				case FP_WINDOW_HORIZONTAL_BARS: pattern = "WINDOW_HORIZONTAL_BARS";		break;
				case FP_WINDOW_SLANT_LEFT:		pattern = "WINDOW_SLANT_LEFT";	break;
				case FP_WINDOW_SLANT_RIGHT:		pattern = "WINDOW_SLANT_RIGHT"; break;
				case FP_WINDOW_SQUARE_DOTS:		pattern = "WINDOW_SQUARE_DOTS"; break;
				case FP_WINDOW_VERTICAL_BARS:	pattern = "WINDOW_VERTICAL_BARS";		break;
				default:						pattern = "** Unrecognized";	break;
			}

			fprintf (state->fp, 
				"(new face rendition: pattern = %s, color = %s, contrast color = %s%s)\n",
				pattern, 
				color_name(buf1, &fr->color, fr->h.display_context),
				color_name(buf2, &fr->contrast_color, fr->h.display_context),
				fr->h.transform_rendition->z_buffering ? ", Z buffering" : "");
		}

		state->last_face_incarnation = fr->h.incarnation;
	}

	local void dump_points (fp, count, points, rend)
		register		FILE			*fp;
		register		int				count;
		register		DC_Point		*points;
		stack			Anyrendition	*rend; {
	
		fprintf (fp, "	  ");
		if (count == 0) fprintf (fp, "(no points!)\n");
		else if (rend->h.transform_rendition->z_buffering) {
			register	int				blops = 0;

			until (--count == 0) {
				fprintf (fp, "(%d, %d, %d) - ", points->x, points->y,points->z);
				++points;

				if (++blops == 3) {
					fprintf (fp, "\n	");
					blops = 0;
				}
			}
			fprintf (fp, "(%d, %d, %d)\n", points->x, points->y, points->z);
		}
		else {
			register	int				blops = 0;

			until (--count == 0) {
				fprintf (fp, "(%d, %d) - ", points->x, points->y);
				++points;

				if (++blops == 5) {
					fprintf (fp, "\n	");
					blops = 0;
				}
			}
			fprintf (fp, "(%d, %d)\n", points->x, points->y);
		}
	}

	local void draw_dc_polyline (lr, count, points)
		stack			Line_Rendition	*lr;
		stack			int				count;
		stack			DC_Point		*points; {
		register		Printf_State	*state = (Printf_State *)lr->h.data;
		
		if (state->fp != null) {
			fprintf (state->fp, "\nPolyline:\n");

			if (lr->h.incarnation != state->last_line_incarnation)
				new_line_rendition (lr);
		
			dump_points (state->fp, count, points, (Anyrendition *)lr);
		}
	}

	local void draw_dc_overlay_polyline (lr, count, points)
		stack			Line_Rendition	*lr;
		stack			int				count;
		stack			DC_Point		*points; {
		register		Printf_State	*state = (Printf_State *)lr->h.data;
		
		if (state->fp != null) {
			fprintf (state->fp, "\nOVERLAY Polyline:\n");

			if (lr->h.incarnation != state->last_line_incarnation)
				new_line_rendition (lr);
		
			dump_points (state->fp, count, points, (Anyrendition *)lr);
		}
	}

	local void draw_dc_face (fr, count, points)
		stack			Face_Rendition			*fr;
		stack			int						count;
		stack			DC_Point				*points; {
		register		Printf_State			*state = (Printf_State *)fr->h.data;
		
		if (state->fp != null) {
			fprintf (state->fp, "\nPolygon face:\n");

			if (fr->h.incarnation != state->last_face_incarnation)
				new_face_rendition (fr);
		
			dump_points (state->fp, count, points, (Anyrendition *)fr);
		}
	}

	local void draw_dc_blended_face (fr, count, points, 
									 color_count, colors, patterns)
		stack		Face_Rendition		*fr;
		stack		int					count;
		stack		DC_Point			*points; 
		stack		int					color_count;
		stack		Color_Index			*colors;
		stack		int					*patterns; {
		register	Printf_State		*state = (Printf_State *)fr->h.data;
		
		if (state->fp != null) {
			fprintf (state->fp, "\nPolygon BLENDED face:\n");

			if (fr->h.incarnation != state->last_face_incarnation)
				new_face_rendition (fr);
		
			dump_points (state->fp, count, points, (Anyrendition *)fr);
		}
	}

	local void draw_dc_overlay_face (fr, count, points)
		stack			Face_Rendition			*fr;
		stack			int						count;
		stack			DC_Point				*points; {
		register		Printf_State			*state = (Printf_State *)fr->h.data;
		
		if (state->fp != null) {
			fprintf (state->fp, "\nPolygon OVERLAY face:\n");

			if (fr->h.incarnation != state->last_face_incarnation)
				new_face_rendition (fr);
		
			dump_points (state->fp, count, points, (Anyrendition *)fr);
		}
	}

	local void set_device_color_map (dc, r, g, b, index)
		stack		Display_Context			*dc;
		stack		int						r, g, b;
		stack		int						index; {
		register	Printf_State			*state =(Printf_State *) dc->data;

		if (state->fp != null) fprintf (state->fp, "set_device_color_map() --- entry %3d set to %3d %3d %3d\n",
			index, r, g, b);
	}

	local void draw_raster (mr, where, count, craster)
		stack		Misc_Rendition		*mr;
		stack		DC_Point			*where;
		stack		int					count;
		stack		char				*craster; {
		register	Printf_State		*state =(Printf_State *)mr->h.data;

		if (state->fp != null) fprintf (state->fp, "draw_raster()\n");
	}

	local void draw_dc_pixel_array (mr, where, count, hoffset, hcount, rasters)
		stack		Misc_Rendition		*mr;
		stack		DC_Point			*where;
		stack		int					count, hoffset, hcount;
		stack		Color_Index			**rasters; {
		register	Printf_State		*state =(Printf_State *)mr->h.data;

		if (state->fp != null) fprintf (state->fp, "draw_pixel_array()\n");

		HD_Pixar_To_Byte_Rasters (mr, where, count, hoffset, hcount, rasters,
								  ADDR(draw_raster));
	}

	local boolean request_location (dc, button, x, y)
		stack		Display_Context			*dc;
		stack		int						*button;
		stack		int						*x, *y; {
		register	Printf_State			*state =(Printf_State *) dc->data;

		if (state->fp != null) fprintf (state->fp, "request_location()\n");

		state->last_button = ++state->last_button % 10;
		*button = (state->last_button > 7) ? 1 : 0;
		*x = *y = state->last_mouse = (state->last_mouse + 100) % 800;

		if (state->fp != null) {
			fprintf (state->fp, "Mouse coordinates returned = %4d %4d \n", *x, *y);
			fprintf (state->fp, "Mouse button returned = %4d\n", *button);
		}

		return true;
	}

	local boolean request_keyboard (dc, button, status)
		stack		Display_Context			*dc;
		stack		int						*button,
											*status; {
		register	Printf_State			*state = (Printf_State *) dc->data;

		if (state->fp != null) fprintf (state->fp, "request_keyboard()\n");

		state->last_keyboard = ++state->last_keyboard % 4;
		if (state->last_keyboard == 0) {
			*button = 'A';
			*status = 0;

			if (state->fp != null) fprintf (state->fp, "Keyboard returned = '%c' %4d\n", *button, *status);

			HI_Queue_Keyboard_Event (dc->actor, *button, *status);
		}
		return false;
	}

	local void get_actions (at)
		register	Action_Table			*at; {

		at->start_device				= ADDR (start_device);
		at->resize_outer_window			= ADDR (resize_outer_window);
		at->free_outer_window			= ADDR (free_outer_window);
		at->get_outer_window			= ADDR (get_outer_window);
		at->clear_z_buffer				= ADDR (clear_z_buffer);
		at->get_physical_info			= ADDR (get_physical_info);
		at->stop_device					= ADDR (stop_device);
		at->init_picture				= ADDR (init_picture);
		at->finish_picture				= ADDR (finish_picture);
		at->draw_dc_polyline			= ADDR (draw_dc_polyline);
		at->draw_dc_face				= ADDR (draw_dc_face);
		at->draw_dc_overlay_polyline	= ADDR (draw_dc_overlay_polyline);
		at->draw_dc_overlay_face		= ADDR (draw_dc_overlay_face);
		at->draw_dc_blended_face		= ADDR (draw_dc_blended_face);
		at->set_device_color_map		= ADDR (set_device_color_map);
		at->draw_dc_pixel_array			= ADDR (draw_dc_pixel_array);
		at->request_location			= ADDR (request_location);
		at->request_keyboard			= ADDR (request_keyboard);
	}
#endif

/* (mustn't end with a '#' line) */
