home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / graphics / 3d / icoons / source / render.c < prev    next >
C/C++ Source or Header  |  1992-10-23  |  14KB  |  499 lines

  1. /* :ts=8 */    /* Yes some of us still use vi ! */
  2. /************************************************************************/
  3. /*                                                                      */
  4. /* This file contains code which is called from tesselate.c to render     */
  5. /* the current object.                            */
  6. /*                                                                      */
  7. /************************************************************************/
  8.  
  9. #include <math.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include <errno.h>
  14. #include <stdlib.h>
  15.  
  16.     /* SIPP include files: */
  17. #include "sipp.h"
  18. #include "shaders.h"
  19.  
  20. #include "general.h"
  21. #include "globals.h"
  22. #include "intui.h"
  23. #include "spl_gfx.h"
  24. #include "tesselate.h"
  25. #include "render.h"
  26.  
  27. static Strauss_desc    Strauss_Shader_Data;
  28. static double         Min_Value;
  29. static double         Max_Value;
  30. static double        View_Distance;
  31. static SObject        *SIPP_Object         = NULL;
  32.  
  33. static int            Current_Pen         = -1;
  34.  
  35. static Byte_T         *Error_Diffusion_Table     = NULL;
  36.  
  37. static
  38. void Error_Diffusion_Free()
  39. /************************************************************************/
  40. /*                                    */
  41. /* Free work space used by the Floyd-Steinberg algorithm.        */
  42. /*                                    */
  43. /************************************************************************/
  44. {
  45.     int i;
  46.    
  47.     if (Error_Diffusion_Table == NULL) return;
  48.  
  49.     free(Error_Diffusion_Table);
  50.     Error_Diffusion_Table = NULL; 
  51.  
  52. } /* Error_Diffusion_Free */
  53.  
  54. static
  55. void Error_Diffusion_Init()
  56. /************************************************************************/
  57. /*                                    */
  58. /* Allocate and initialize workspace used by the Floyd-Steinberg     */
  59. /* algorithm.                                */
  60. /*                                    */
  61. /************************************************************************/
  62. {
  63.     int i;
  64.  
  65.     Error_Diffusion_Free();
  66.     
  67.     Error_Diffusion_Table = (Byte_T *) 
  68.             malloc(Screen_Width * sizeof(Byte_T)+1);
  69.     if (Error_Diffusion_Table == NULL) {
  70.  
  71.     Display_Error_Message("Couldn't allocate memory");
  72.     CloseStuff();
  73.     exit(2);
  74.  
  75.     } /* if */
  76.  
  77.     for (i = 0; i < Screen_Width; i++) Error_Diffusion_Table[i] = 0;
  78.  
  79. } /* Error_Diffusion_Init */
  80.  
  81.  
  82. static
  83. short Error_Diffusion_Correct(int X, short Value)
  84. /************************************************************************/
  85. /*                                    */
  86. /* Compute and return actual pen id to be used to plot a color at column*/
  87. /* X with the value 'Value' (0 - 255).                    */
  88. /* We use a slightly modified Floyd-Steinberg error diffusion algoritm    */
  89. /* to do this.                                */
  90. /*                                    */
  91. /* The modification is that the below-right term is ignored.        */
  92. /*                                    */
  93. /************************************************************************/
  94. {
  95.     short Pen, E, E_Right, E_BelowLeft, E_Below;
  96.  
  97.     Value  += Error_Diffusion_Table[X]; /* Correct for earlier error */
  98.     Pen = (Value + 8) >> 4;
  99.     E      = Value - (Pen << 4);    /* Error */
  100.    
  101.     E_Right     = ((7 * E) + 8) >> 4;
  102.     E_BelowLeft = ((3 * E) + 8) >> 4;
  103.     E_Below     =  E - E_Right - E_BelowLeft;
  104.  
  105.     Error_Diffusion_Table[X+1] += E_Right;     /* right     */
  106.     Error_Diffusion_Table[X-1] += E_BelowLeft;    /* Below left     */
  107.     Error_Diffusion_Table[X]    = E_Below;     /* Below     */
  108.  
  109.     return(Pen);
  110.  
  111. } /* Error_Diffusion_Correct */
  112.  
  113. static
  114. void Set_Color_Table_Gray(Boolean_T On)
  115. /************************************************************************/
  116. /*                                    */
  117. /* If On is TRUE, then set the colortable to a grayscale, otherwise    */
  118. /* restore the colortable.                        */
  119. /*                                    */
  120. /************************************************************************/
  121. {
  122.     int i;
  123.  
  124.     if (On) {
  125.  
  126.     for (i = 0; i < 16; i++)
  127.          SetRGB4(Windows[Id_Active_Window].ViewPort,  i, i, i, i); 
  128.  
  129.     } else {
  130.  
  131.     for (i = 0; i < 16 && ScreenColors[i].ColorIndex >= 0; i++)
  132.          SetRGB4(Windows[Id_Active_Window].ViewPort,  
  133.                     ScreenColors[i].ColorIndex,
  134.                     ScreenColors[i].Red,
  135.                     ScreenColors[i].Green,
  136.                     ScreenColors[i].Blue);
  137.     }
  138. } /* Set_Color_Table_Gray */
  139.  
  140. static
  141. void Draw_Line(char *Data,         /* Not used     */
  142.           int Col1, int Row1,     /* Start pos    */
  143.           int Col2, int Row2)    /* End pos    */
  144. /************************************************************************/
  145. /*                                    */
  146. /* Draw a line from (Col1, Row1) to (Col2, Row2).            */
  147. /*                                    */
  148. /************************************************************************/
  149. {
  150.     short    X1, Y1, X2, Y2;
  151.  
  152.     if (Current_Pen < 0) {
  153.       Current_Pen = 1;
  154.         SetAPen(Windows[Id_Active_Window].RastPort, Current_Pen);
  155.     }
  156.  
  157.     X1 = Views[V_P].X_Min + (Col1 << 1);
  158.     Y1 = Views[V_P].Y_Min + Row1;
  159.     X2 = Views[V_P].X_Min + (Col2 << 1);
  160.     Y2 = Views[V_P].Y_Min + Row2;
  161.  
  162.     Move(Windows[Id_Active_Window].RastPort, X1, Y1);
  163.     Draw(Windows[Id_Active_Window].RastPort, X2, Y2);
  164.  
  165. } /* Draw_Line */
  166.  
  167. static
  168. void Draw_Pixel(char *Data,         /* Not used    */
  169.         int Col, int Row,     /* Position    */
  170.         unsigned char R,    /* Red        */
  171.         unsigned char G,    /* Green    */
  172.         unsigned char B)    /* Blue        */
  173. /************************************************************************/
  174. /*                                    */
  175. /* Draw a pixel on position (Col, Row) with the color given by R, G, B.    */
  176. /*                                    */
  177. /* Simplifications:                            */
  178. /*                                    */
  179. /* We know that we're working with a monochrome picture, so we only     */
  180. /* look at R (red).                            */
  181. /*                                    */
  182. /* We disregard aspect ratio, but plot 2 horizontal pixels each time    */
  183. /* (corresponding to an aspect ration of 0.91 in PAL).            */
  184. /*                                    */
  185. /* Actual pen is chosen based on a slightly modified Floyd - Steinberg    */
  186. /* error diffusion algoritm.                        */
  187. /*                                    */
  188. /************************************************************************/
  189. {
  190.     short    X, Y;
  191.     int        Pen;
  192.     static int    Old_Row = -1;
  193.  
  194.     if (Old_Row != Row) {
  195.         sprintf(Error_Msg, "Rendering row %d", Row);
  196.         Display_Status(Error_Msg);
  197.     Old_Row = Row;
  198.     }
  199.  
  200.     if (R == 0) {
  201.  
  202.         /* Trick to speed up for black color:            */
  203.         /* Ignore error correction for this pixel, and    return    */
  204.         /* immediately, as we know that all pixels are black by    */
  205.         /* default.                        */
  206.  
  207.         Error_Diffusion_Table[Col]    = 0; 
  208.         return;        /* Not entirely correct, but faster */
  209.  
  210.     } else Pen = Error_Diffusion_Correct(Col, R);
  211.  
  212.         /* We have already set full screen to black, so there's    */
  213.         /* no need to actually plot the black pixels.        */
  214.     if (Pen == 0) return;    
  215.  
  216.     if (Pen != Current_Pen) {
  217.         SetAPen(Windows[Id_Active_Window].RastPort, Pen);
  218.         Current_Pen = Pen;
  219.     }
  220.  
  221.     /* Plot 2 pixels for each column.                */
  222.     X = Views[V_P].X_Min + (Col << 1);
  223.     Y = Views[V_P].Y_Min + Row;
  224.  
  225.     WritePixel(Windows[Id_Active_Window].RastPort, X,   Y);
  226.     WritePixel(Windows[Id_Active_Window].RastPort, X+1, Y);
  227.  
  228.  
  229. } /* Draw_Pixel */
  230.  
  231. static
  232. void Create_SIPP_Polygon(Vector_T Point0, Vector_T Point1, 
  233.                 Vector_T Point2, Vector_T Point3)
  234. /************************************************************************/
  235. /*                                    */
  236. /* Add the square given by the four points to polygon stack.        */
  237. /*                                    */
  238. /************************************************************************/
  239. {
  240.     Boolean_T     Face1_Ok, Face2_Ok;
  241.     int        i;
  242.  
  243.     Face1_Ok = Face_Is_Ok(Point0, Point1, Point2);
  244.     Face2_Ok = Face_Is_Ok(Point1, Point2, Point3);
  245.  
  246.     if (Face1_Ok) {
  247.  
  248.     vertex_push(Point0[0], Point0[1], Point0[2]);
  249.     vertex_push(Point1[0], Point1[1], Point1[2]);
  250.     vertex_push(Point2[0], Point2[1], Point2[2]);
  251.         polygon_push();
  252.  
  253.     for (i = 0; i < 3; i++) { 
  254.         if (Point0[i] < Min_Value) Min_Value = Point0[i];
  255.         if (Point0[i] > Max_Value) Max_Value = Point0[i];
  256.         if (Point1[i] < Min_Value) Min_Value = Point1[i];
  257.         if (Point1[i] > Max_Value) Max_Value = Point1[i];
  258.         if (Point2[i] < Min_Value) Min_Value = Point2[i];
  259.         if (Point2[i] > Max_Value) Max_Value = Point2[i];
  260.       } /* for */
  261.  
  262.     } /* if */
  263.  
  264.     if (Face2_Ok) {
  265.  
  266.     vertex_push(Point2[0], Point2[1], Point2[2]);
  267.     vertex_push(Point1[0], Point1[1], Point1[2]);
  268.     vertex_push(Point3[0], Point3[1], Point3[2]);
  269.         polygon_push();
  270.  
  271.     for (i = 0; i < 3; i++) { 
  272.         if (Point1[i] < Min_Value) Min_Value = Point1[i];
  273.         if (Point1[i] > Max_Value) Max_Value = Point1[i];
  274.         if (Point2[i] < Min_Value) Min_Value = Point2[i];
  275.         if (Point2[i] > Max_Value) Max_Value = Point2[i];
  276.         if (Point3[i] < Min_Value) Min_Value = Point3[i];
  277.         if (Point3[i] > Max_Value) Max_Value = Point3[i];
  278.       } /* for */
  279.  
  280.     } /* if */
  281.  
  282. } /* Create_SIPP_Polygon */
  283.  
  284.  
  285. Boolean_T Render_Setup()
  286. /************************************************************************/
  287. /*                                    */
  288. /* Tesselate the current object, and add faces to SIPP.            */
  289. /* This can take quite some time...                    */
  290. /*                                    */
  291. /************************************************************************/
  292. {
  293.     Tesselate_Info_T    TI;
  294.     Boolean_T        Error;
  295.     Surface        *SIPP_Surface;
  296.     static  Boolean_T    First_Time = TRUE;
  297.  
  298.     Render_Cleanup();
  299.  
  300.     Min_Value = 999999.9;
  301.     Max_Value = -999999.9;
  302.  
  303.     TI.Patch_Begin         = NULL;
  304.     TI.Patch_Generate_Face = Create_SIPP_Polygon;
  305.     TI.Patch_End          = NULL;
  306.  
  307.     if (First_Time) {
  308.  
  309.     First_Time = FALSE;
  310.  
  311.         sipp_init();
  312.  
  313.     } /* if */
  314.  
  315.     Error = Tesselate_Object(&TI);
  316.  
  317.     if (Error) return(Error);
  318.  
  319.     Strauss_Shader_Data.ambient     = 0.0;    /* 0 - 1 */
  320.     Strauss_Shader_Data.smoothness     = 0.5;
  321.     Strauss_Shader_Data.metalness     = 0.5;
  322.     Strauss_Shader_Data.color.red     = 1.0;
  323.     Strauss_Shader_Data.color.grn     = 1.0;
  324.     Strauss_Shader_Data.color.blu     = 1.0;
  325.     Strauss_Shader_Data.opacity.red     = 1.0;
  326.     Strauss_Shader_Data.opacity.grn     = 1.0;
  327.     Strauss_Shader_Data.opacity.blu     = 1.0;
  328.  
  329.     Display_Status("Creating surface");
  330.     SIPP_Surface = surface_create(&Strauss_Shader_Data, strauss_shader);
  331.  
  332.     Display_Status("Creating object");
  333.     SIPP_Object = object_create();
  334.     object_add_surface(SIPP_Object, SIPP_Surface);
  335.  
  336.     object_add_subobj(sipp_world, SIPP_Object);
  337.  
  338.     Min_Value = ABS(Min_Value);
  339.     Max_Value = ABS(Max_Value);
  340.  
  341.     View_Distance  = (Min_Value > Max_Value) ? Min_Value : Max_Value;
  342.     View_Distance  = View_Distance * 3.0;
  343.  
  344.     Display_Status("Render setup done");
  345.  
  346.     return(FALSE);
  347.  
  348. } /* Render_Setup */
  349.  
  350. void Render_Cleanup()
  351. /************************************************************************/
  352. /*                                    */
  353. /* Free memory etc. used in rendering.                    */
  354. /*                                    */
  355. /************************************************************************/
  356. {
  357.     if (SIPP_Object == NULL) return;
  358.  
  359.     object_sub_subobj(sipp_world, SIPP_Object);
  360.     object_delete(SIPP_Object);
  361.  
  362.     SIPP_Object = NULL;
  363.  
  364. } /* Render_Cleanup */
  365.  
  366. Boolean_T Render_Object()
  367. /************************************************************************/
  368. /*                                    */
  369. /* render the current object.                        */
  370. /*                                    */
  371. /* Render_Setup should be called before this routine.            */
  372. /* Render_Cleanup should be called later to release memory etc.        */
  373. /*                                    */
  374. /************************************************************************/
  375. {
  376.     Vector_T        P, RP;
  377.     Boolean_T        Error;
  378.     Lightsource        *SIPP_Lightsource;
  379.     int            Width, Height;
  380.     int            Mode;
  381.  
  382.     if (SIPP_Object == NULL) return(TRUE);
  383.  
  384.     Set_Pointer(TRUE);
  385.  
  386.     Error_Diffusion_Init();
  387.  
  388.     switch (Rendering_Mode) {
  389.  
  390.     case RM_Phong    : Mode = PHONG;     break;
  391.     case RM_Gouraud    : Mode = GOURAUD;     break;
  392.     case RM_Flat    : Mode = FLAT;        break;
  393.     case RM_Line    : Mode = LINE;      break;
  394.     default        : Mode = LINE;        break;
  395.  
  396.     } /* switch */
  397.  
  398.     P[0] = 0.0;         
  399.     P[1] = -View_Distance;
  400.     P[2] = 0.0;
  401.  
  402.     Compute_Inverse_Rotation_Matrix(M_InvRotation, Rotation_Vector);
  403.     Matrix_MultV(RP, M_InvRotation, P);
  404.  
  405.     sipp_show_backfaces(!Backface_Culling);
  406.  
  407.     camera_params(sipp_camera, 
  408.         RP[0], RP[1], RP[2],
  409.         0.0, 0.0, 0.0,        /* Look at    */
  410.         0.0, 0.0, 1.0,        /* Up vector       */
  411.         0.4);            /* Focal factor    */
  412.  
  413.     SIPP_Lightsource =     lightsource_create(
  414.             2.0*RP[0], 2.0*RP[1], 2.0*RP[2], /* Position     */
  415.             1.0, 1.0, 1.0,         /* Color (RGB)    */
  416.             LIGHT_DIRECTION);
  417.  
  418.  
  419.     Display_Status("Rendering image");
  420.     Current_Pen = -1;
  421.     Width  = Views[Id_Active_Window].X_Max - 
  422.          Views[Id_Active_Window].X_Min + 1;
  423.     Height = Views[Id_Active_Window].Y_Max - 
  424.              Views[Id_Active_Window].Y_Min + 1;
  425.  
  426.     Width  = Width / 2;
  427.  
  428.     if (Mode != LINE) {
  429.  
  430.     Set_Color_Table_Gray(TRUE);
  431.  
  432.         Clear_All(What_P);
  433.  
  434.         render_image_func(
  435.         Width,            /* Width    */
  436.         Height,            /* Height    */
  437.         Draw_Pixel,        /* Function    */
  438.         0,            /* Data     */
  439.         Mode,            /* Mode        */
  440.         1);            /* Oversampling    */
  441.  
  442.         Display_Status("Rendering Done. Press spacebar");
  443.  
  444.     while (Wait_For_Key() != ' ') ; 
  445.  
  446.     Set_Color_Table_Gray(FALSE);
  447.         Redraw_Mask |= What_All;
  448.  
  449.     } else {
  450.  
  451.         Clear_All(What_P);
  452.  
  453.         render_image_func(
  454.         Width,            /* Width    */
  455.         Height,            /* Height    */
  456.         Draw_Line,        /* Function    */
  457.         0,            /* Data     */
  458.         LINE,            /* Mode        */
  459.         1);            /* Oversampling    */
  460.  
  461.         Display_Status("Rendering Done. Press spacebar");
  462.  
  463.     while (Wait_For_Key() != ' ') ; 
  464.  
  465.         Redraw_Mask |= What_All;
  466.  
  467.     } /* if .. else .. */
  468.  
  469.     Display_Status(NULL);
  470.  
  471.     light_destruct(SIPP_Lightsource);
  472.  
  473.     Error_Diffusion_Free();
  474.  
  475.     Set_Pointer(FALSE);
  476.  
  477.     return(FALSE);
  478.  
  479. } /* Render_Object */
  480.  
  481. Boolean_T Render_Tesselate_Object()
  482. /************************************************************************/
  483. /*                                    */
  484. /* Tesselate the current object, and render it.                */
  485. /*                                    */
  486. /************************************************************************/
  487. {
  488.     Boolean_T        Error;
  489.  
  490.     Set_Pointer(TRUE);
  491.  
  492.     if (Render_Setup()) return(TRUE);
  493.  
  494.     Error = Render_Object();
  495.  
  496.     return(Error);
  497.  
  498. } /* Render_Tesselate_Object */
  499.