home *** CD-ROM | disk | FTP | other *** search
- /* :ts=8 */ /* Yes some of us still use vi ! */
- /************************************************************************/
- /* */
- /* This file contains code which is called from tesselate.c to render */
- /* the current object. */
- /* */
- /************************************************************************/
-
- #include <math.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
- #include <stdlib.h>
-
- /* SIPP include files: */
- #include "sipp.h"
- #include "shaders.h"
-
- #include "general.h"
- #include "globals.h"
- #include "intui.h"
- #include "spl_gfx.h"
- #include "tesselate.h"
- #include "render.h"
-
- static Strauss_desc Strauss_Shader_Data;
- static double Min_Value;
- static double Max_Value;
- static double View_Distance;
- static SObject *SIPP_Object = NULL;
-
- static int Current_Pen = -1;
-
- static Byte_T *Error_Diffusion_Table = NULL;
-
- static
- void Error_Diffusion_Free()
- /************************************************************************/
- /* */
- /* Free work space used by the Floyd-Steinberg algorithm. */
- /* */
- /************************************************************************/
- {
- int i;
-
- if (Error_Diffusion_Table == NULL) return;
-
- free(Error_Diffusion_Table);
- Error_Diffusion_Table = NULL;
-
- } /* Error_Diffusion_Free */
-
- static
- void Error_Diffusion_Init()
- /************************************************************************/
- /* */
- /* Allocate and initialize workspace used by the Floyd-Steinberg */
- /* algorithm. */
- /* */
- /************************************************************************/
- {
- int i;
-
- Error_Diffusion_Free();
-
- Error_Diffusion_Table = (Byte_T *)
- malloc(Screen_Width * sizeof(Byte_T)+1);
- if (Error_Diffusion_Table == NULL) {
-
- Display_Error_Message("Couldn't allocate memory");
- CloseStuff();
- exit(2);
-
- } /* if */
-
- for (i = 0; i < Screen_Width; i++) Error_Diffusion_Table[i] = 0;
-
- } /* Error_Diffusion_Init */
-
-
- static
- short Error_Diffusion_Correct(int X, short Value)
- /************************************************************************/
- /* */
- /* Compute and return actual pen id to be used to plot a color at column*/
- /* X with the value 'Value' (0 - 255). */
- /* We use a slightly modified Floyd-Steinberg error diffusion algoritm */
- /* to do this. */
- /* */
- /* The modification is that the below-right term is ignored. */
- /* */
- /************************************************************************/
- {
- short Pen, E, E_Right, E_BelowLeft, E_Below;
-
- Value += Error_Diffusion_Table[X]; /* Correct for earlier error */
- Pen = (Value + 8) >> 4;
- E = Value - (Pen << 4); /* Error */
-
- E_Right = ((7 * E) + 8) >> 4;
- E_BelowLeft = ((3 * E) + 8) >> 4;
- E_Below = E - E_Right - E_BelowLeft;
-
- Error_Diffusion_Table[X+1] += E_Right; /* right */
- Error_Diffusion_Table[X-1] += E_BelowLeft; /* Below left */
- Error_Diffusion_Table[X] = E_Below; /* Below */
-
- return(Pen);
-
- } /* Error_Diffusion_Correct */
-
- static
- void Set_Color_Table_Gray(Boolean_T On)
- /************************************************************************/
- /* */
- /* If On is TRUE, then set the colortable to a grayscale, otherwise */
- /* restore the colortable. */
- /* */
- /************************************************************************/
- {
- int i;
-
- if (On) {
-
- for (i = 0; i < 16; i++)
- SetRGB4(Windows[Id_Active_Window].ViewPort, i, i, i, i);
-
- } else {
-
- for (i = 0; i < 16 && ScreenColors[i].ColorIndex >= 0; i++)
- SetRGB4(Windows[Id_Active_Window].ViewPort,
- ScreenColors[i].ColorIndex,
- ScreenColors[i].Red,
- ScreenColors[i].Green,
- ScreenColors[i].Blue);
- }
- } /* Set_Color_Table_Gray */
-
- static
- void Draw_Line(char *Data, /* Not used */
- int Col1, int Row1, /* Start pos */
- int Col2, int Row2) /* End pos */
- /************************************************************************/
- /* */
- /* Draw a line from (Col1, Row1) to (Col2, Row2). */
- /* */
- /************************************************************************/
- {
- short X1, Y1, X2, Y2;
-
- if (Current_Pen < 0) {
- Current_Pen = 1;
- SetAPen(Windows[Id_Active_Window].RastPort, Current_Pen);
- }
-
- X1 = Views[V_P].X_Min + (Col1 << 1);
- Y1 = Views[V_P].Y_Min + Row1;
- X2 = Views[V_P].X_Min + (Col2 << 1);
- Y2 = Views[V_P].Y_Min + Row2;
-
- Move(Windows[Id_Active_Window].RastPort, X1, Y1);
- Draw(Windows[Id_Active_Window].RastPort, X2, Y2);
-
- } /* Draw_Line */
-
- static
- void Draw_Pixel(char *Data, /* Not used */
- int Col, int Row, /* Position */
- unsigned char R, /* Red */
- unsigned char G, /* Green */
- unsigned char B) /* Blue */
- /************************************************************************/
- /* */
- /* Draw a pixel on position (Col, Row) with the color given by R, G, B. */
- /* */
- /* Simplifications: */
- /* */
- /* We know that we're working with a monochrome picture, so we only */
- /* look at R (red). */
- /* */
- /* We disregard aspect ratio, but plot 2 horizontal pixels each time */
- /* (corresponding to an aspect ration of 0.91 in PAL). */
- /* */
- /* Actual pen is chosen based on a slightly modified Floyd - Steinberg */
- /* error diffusion algoritm. */
- /* */
- /************************************************************************/
- {
- short X, Y;
- int Pen;
- static int Old_Row = -1;
-
- if (Old_Row != Row) {
- sprintf(Error_Msg, "Rendering row %d", Row);
- Display_Status(Error_Msg);
- Old_Row = Row;
- }
-
- if (R == 0) {
-
- /* Trick to speed up for black color: */
- /* Ignore error correction for this pixel, and return */
- /* immediately, as we know that all pixels are black by */
- /* default. */
-
- Error_Diffusion_Table[Col] = 0;
- return; /* Not entirely correct, but faster */
-
- } else Pen = Error_Diffusion_Correct(Col, R);
-
- /* We have already set full screen to black, so there's */
- /* no need to actually plot the black pixels. */
- if (Pen == 0) return;
-
- if (Pen != Current_Pen) {
- SetAPen(Windows[Id_Active_Window].RastPort, Pen);
- Current_Pen = Pen;
- }
-
- /* Plot 2 pixels for each column. */
- X = Views[V_P].X_Min + (Col << 1);
- Y = Views[V_P].Y_Min + Row;
-
- WritePixel(Windows[Id_Active_Window].RastPort, X, Y);
- WritePixel(Windows[Id_Active_Window].RastPort, X+1, Y);
-
-
- } /* Draw_Pixel */
-
- static
- void Create_SIPP_Polygon(Vector_T Point0, Vector_T Point1,
- Vector_T Point2, Vector_T Point3)
- /************************************************************************/
- /* */
- /* Add the square given by the four points to polygon stack. */
- /* */
- /************************************************************************/
- {
- Boolean_T Face1_Ok, Face2_Ok;
- int i;
-
- Face1_Ok = Face_Is_Ok(Point0, Point1, Point2);
- Face2_Ok = Face_Is_Ok(Point1, Point2, Point3);
-
- if (Face1_Ok) {
-
- vertex_push(Point0[0], Point0[1], Point0[2]);
- vertex_push(Point1[0], Point1[1], Point1[2]);
- vertex_push(Point2[0], Point2[1], Point2[2]);
- polygon_push();
-
- for (i = 0; i < 3; i++) {
- if (Point0[i] < Min_Value) Min_Value = Point0[i];
- if (Point0[i] > Max_Value) Max_Value = Point0[i];
- if (Point1[i] < Min_Value) Min_Value = Point1[i];
- if (Point1[i] > Max_Value) Max_Value = Point1[i];
- if (Point2[i] < Min_Value) Min_Value = Point2[i];
- if (Point2[i] > Max_Value) Max_Value = Point2[i];
- } /* for */
-
- } /* if */
-
- if (Face2_Ok) {
-
- vertex_push(Point2[0], Point2[1], Point2[2]);
- vertex_push(Point1[0], Point1[1], Point1[2]);
- vertex_push(Point3[0], Point3[1], Point3[2]);
- polygon_push();
-
- for (i = 0; i < 3; i++) {
- if (Point1[i] < Min_Value) Min_Value = Point1[i];
- if (Point1[i] > Max_Value) Max_Value = Point1[i];
- if (Point2[i] < Min_Value) Min_Value = Point2[i];
- if (Point2[i] > Max_Value) Max_Value = Point2[i];
- if (Point3[i] < Min_Value) Min_Value = Point3[i];
- if (Point3[i] > Max_Value) Max_Value = Point3[i];
- } /* for */
-
- } /* if */
-
- } /* Create_SIPP_Polygon */
-
-
- Boolean_T Render_Setup()
- /************************************************************************/
- /* */
- /* Tesselate the current object, and add faces to SIPP. */
- /* This can take quite some time... */
- /* */
- /************************************************************************/
- {
- Tesselate_Info_T TI;
- Boolean_T Error;
- Surface *SIPP_Surface;
- static Boolean_T First_Time = TRUE;
-
- Render_Cleanup();
-
- Min_Value = 999999.9;
- Max_Value = -999999.9;
-
- TI.Patch_Begin = NULL;
- TI.Patch_Generate_Face = Create_SIPP_Polygon;
- TI.Patch_End = NULL;
-
- if (First_Time) {
-
- First_Time = FALSE;
-
- sipp_init();
-
- } /* if */
-
- Error = Tesselate_Object(&TI);
-
- if (Error) return(Error);
-
- Strauss_Shader_Data.ambient = 0.0; /* 0 - 1 */
- Strauss_Shader_Data.smoothness = 0.5;
- Strauss_Shader_Data.metalness = 0.5;
- Strauss_Shader_Data.color.red = 1.0;
- Strauss_Shader_Data.color.grn = 1.0;
- Strauss_Shader_Data.color.blu = 1.0;
- Strauss_Shader_Data.opacity.red = 1.0;
- Strauss_Shader_Data.opacity.grn = 1.0;
- Strauss_Shader_Data.opacity.blu = 1.0;
-
- Display_Status("Creating surface");
- SIPP_Surface = surface_create(&Strauss_Shader_Data, strauss_shader);
-
- Display_Status("Creating object");
- SIPP_Object = object_create();
- object_add_surface(SIPP_Object, SIPP_Surface);
-
- object_add_subobj(sipp_world, SIPP_Object);
-
- Min_Value = ABS(Min_Value);
- Max_Value = ABS(Max_Value);
-
- View_Distance = (Min_Value > Max_Value) ? Min_Value : Max_Value;
- View_Distance = View_Distance * 3.0;
-
- Display_Status("Render setup done");
-
- return(FALSE);
-
- } /* Render_Setup */
-
- void Render_Cleanup()
- /************************************************************************/
- /* */
- /* Free memory etc. used in rendering. */
- /* */
- /************************************************************************/
- {
- if (SIPP_Object == NULL) return;
-
- object_sub_subobj(sipp_world, SIPP_Object);
- object_delete(SIPP_Object);
-
- SIPP_Object = NULL;
-
- } /* Render_Cleanup */
-
- Boolean_T Render_Object()
- /************************************************************************/
- /* */
- /* render the current object. */
- /* */
- /* Render_Setup should be called before this routine. */
- /* Render_Cleanup should be called later to release memory etc. */
- /* */
- /************************************************************************/
- {
- Vector_T P, RP;
- Boolean_T Error;
- Lightsource *SIPP_Lightsource;
- int Width, Height;
- int Mode;
-
- if (SIPP_Object == NULL) return(TRUE);
-
- Set_Pointer(TRUE);
-
- Error_Diffusion_Init();
-
- switch (Rendering_Mode) {
-
- case RM_Phong : Mode = PHONG; break;
- case RM_Gouraud : Mode = GOURAUD; break;
- case RM_Flat : Mode = FLAT; break;
- case RM_Line : Mode = LINE; break;
- default : Mode = LINE; break;
-
- } /* switch */
-
- P[0] = 0.0;
- P[1] = -View_Distance;
- P[2] = 0.0;
-
- Compute_Inverse_Rotation_Matrix(M_InvRotation, Rotation_Vector);
- Matrix_MultV(RP, M_InvRotation, P);
-
- sipp_show_backfaces(!Backface_Culling);
-
- camera_params(sipp_camera,
- RP[0], RP[1], RP[2],
- 0.0, 0.0, 0.0, /* Look at */
- 0.0, 0.0, 1.0, /* Up vector */
- 0.4); /* Focal factor */
-
- SIPP_Lightsource = lightsource_create(
- 2.0*RP[0], 2.0*RP[1], 2.0*RP[2], /* Position */
- 1.0, 1.0, 1.0, /* Color (RGB) */
- LIGHT_DIRECTION);
-
-
- Display_Status("Rendering image");
- Current_Pen = -1;
- Width = Views[Id_Active_Window].X_Max -
- Views[Id_Active_Window].X_Min + 1;
- Height = Views[Id_Active_Window].Y_Max -
- Views[Id_Active_Window].Y_Min + 1;
-
- Width = Width / 2;
-
- if (Mode != LINE) {
-
- Set_Color_Table_Gray(TRUE);
-
- Clear_All(What_P);
-
- render_image_func(
- Width, /* Width */
- Height, /* Height */
- Draw_Pixel, /* Function */
- 0, /* Data */
- Mode, /* Mode */
- 1); /* Oversampling */
-
- Display_Status("Rendering Done. Press spacebar");
-
- while (Wait_For_Key() != ' ') ;
-
- Set_Color_Table_Gray(FALSE);
- Redraw_Mask |= What_All;
-
- } else {
-
- Clear_All(What_P);
-
- render_image_func(
- Width, /* Width */
- Height, /* Height */
- Draw_Line, /* Function */
- 0, /* Data */
- LINE, /* Mode */
- 1); /* Oversampling */
-
- Display_Status("Rendering Done. Press spacebar");
-
- while (Wait_For_Key() != ' ') ;
-
- Redraw_Mask |= What_All;
-
- } /* if .. else .. */
-
- Display_Status(NULL);
-
- light_destruct(SIPP_Lightsource);
-
- Error_Diffusion_Free();
-
- Set_Pointer(FALSE);
-
- return(FALSE);
-
- } /* Render_Object */
-
- Boolean_T Render_Tesselate_Object()
- /************************************************************************/
- /* */
- /* Tesselate the current object, and render it. */
- /* */
- /************************************************************************/
- {
- Boolean_T Error;
-
- Set_Pointer(TRUE);
-
- if (Render_Setup()) return(TRUE);
-
- Error = Render_Object();
-
- return(Error);
-
- } /* Render_Tesselate_Object */
-