diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2018-08-12 21:59:38 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2018-08-12 21:59:38 +0000 |
commit | d3cea986a286392f9e52464f7aec932fc9921417 (patch) | |
tree | fef21050247bd1cb5401ecb01e9f9befc4e14576 /generator | |
parent | 2c880103c0b55ca5c15bc9e957c3460cdd20d18b (diff) | |
download | netpbm-mirror-d3cea986a286392f9e52464f7aec932fc9921417.tar.gz netpbm-mirror-d3cea986a286392f9e52464f7aec932fc9921417.tar.xz netpbm-mirror-d3cea986a286392f9e52464f7aec932fc9921417.zip |
split common.h into separate interface header files
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@3299 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'generator')
-rw-r--r-- | generator/pamtris/boundaries.c | 44 | ||||
-rw-r--r-- | generator/pamtris/boundaries.h | 69 | ||||
-rw-r--r-- | generator/pamtris/common.h | 437 | ||||
-rw-r--r-- | generator/pamtris/depend.mk | 61 | ||||
-rw-r--r-- | generator/pamtris/fract.h | 54 | ||||
-rw-r--r-- | generator/pamtris/framebuffer.c | 84 | ||||
-rw-r--r-- | generator/pamtris/framebuffer.h | 75 | ||||
-rw-r--r-- | generator/pamtris/input.c | 30 | ||||
-rw-r--r-- | generator/pamtris/input.h | 31 | ||||
-rw-r--r-- | generator/pamtris/limits_pamtris.h | 7 | ||||
-rw-r--r-- | generator/pamtris/pamtris.c | 13 | ||||
-rw-r--r-- | generator/pamtris/triangle.c | 13 | ||||
-rw-r--r-- | generator/pamtris/triangle.h | 17 | ||||
-rw-r--r-- | generator/pamtris/utils.c | 71 | ||||
-rw-r--r-- | generator/pamtris/utils.h | 41 |
15 files changed, 553 insertions, 494 deletions
diff --git a/generator/pamtris/boundaries.c b/generator/pamtris/boundaries.c index 04237e59..e11ea894 100644 --- a/generator/pamtris/boundaries.c +++ b/generator/pamtris/boundaries.c @@ -1,12 +1,32 @@ +/*============================================================================= + boundaries.c +=============================================================================== + Boundary buffer functions + + New triangles are drawn one scanline at a time, and for every such scanline + we have left and right boundary columns within the frame buffer such that + the fraction of the triangle's area within that scanline is enclosed + between those two points (inclusive). Those coordinates may correspond to + columns outside the frame buffer's actual limits, in which case proper + post-processing should be made wherever such coordinates are used to + actually plot anything into the frame buffer. +=============================================================================*/ + #include <stdlib.h> -#include "common.h" +#include <netpbm/mallocvar.h> + +#include "utils.h" +#include "fract.h" + + +#include "boundaries.h" static fract make_pos_fract(int32_t const quotient, - int32_t const remainder) { + int32_t const remainder) { fract retval; @@ -39,7 +59,18 @@ gen_triangle_boundaries(int32_t xy[3][2], boundary_info * bi, int16_t width, int16_t height) { - +/*---------------------------------------------------------------------------- + Generate an entry in the boundary buffer for the boundaries of every + VISIBLE row of a particular triangle. In case there is no such row, + start_row is accordingly set to -1. The argument is a 3-element array + of pairs of int16_t's representing the coordinates of the vertices of + a triangle. Those vertices MUST be already sorted in order from the + uppermost to the lowermost vertex (which is what draw_triangle, the + only function which uses this one, does with the help of sort3). + + The return value indicates whether the middle vertex is to the left of the + line connecting the top vertex to the bottom vertex or not. +-----------------------------------------------------------------------------*/ int16_t leftmost_x = xy[0][0]; int16_t rightmost_x = xy[0][0]; int mid_is_to_the_left; @@ -277,7 +308,12 @@ get_triangle_boundaries(uint16_t row_index, int32_t * left, int32_t * right, const boundary_info * bi) { - +/*---------------------------------------------------------------------------- + Return the left and right boundaries for a given VISIBLE triangle row (the + row index is relative to the first visible row). These values may be out of + the horizontal limits of the frame buffer, which is necessary in order to + compute correct attribute interpolations. +-----------------------------------------------------------------------------*/ uint32_t i = row_index << 1; *left = bi->buffer[i]; diff --git a/generator/pamtris/boundaries.h b/generator/pamtris/boundaries.h new file mode 100644 index 00000000..639a3d3e --- /dev/null +++ b/generator/pamtris/boundaries.h @@ -0,0 +1,69 @@ +#ifndef BOUNDARIES_H_INCLUDED +#define BOUNDARIES_H_INCLUDED + +#include <stdint.h> + +typedef struct boundary_info { +/*---------------------------------------------------------------------------- + Information about visible triangle rows' boundaries. Also see the + "boundary buffer functions" below. + + A "visible" triangle row is one which: + + 1. Corresponds to a frame buffer row whose index (from top to bottom) is + equal to or greater than 0 and smaller than the image height; and + + 2. Has at least some of its pixels between the frame buffer columns whose + index (from left to right) is equal to or greater than 0 and smaller + than the image width. +-----------------------------------------------------------------------------*/ + int16_t start_scanline; + /* Index of the frame buffer scanline which contains the first visible + row of the current triangle, if there is any such row. If not, it + contains the value -1. + */ + + int16_t num_upper_rows; + /* The number of visible rows in the upper part of the triangle. The + upper part of a triangle is composed of all the rows starting from + the top vertex down to the middle vertex, but not including this + last one. + */ + + int16_t num_lower_rows; + /* The number of visible rows in the lower part of the triangle. The + lower part of a triangle is composed of all the rows from the + middle vertex to the bottom vertex -- all inclusive. + */ + + int16_t * buffer; + /* This is the "boundary buffer": a pointer to an array of int16_t's + where each consecutive pair of values indicates, in this order, the + columns of the left and right boundary pixels for a particular + visible triangle row. Those boundaries are inclusive on both sides + and may be outside the limits of the frame buffer. This field is + initialized and freed by the functions "init_boundary_buffer" and + "free_boundary_buffer", respectively. + */ +} boundary_info; + +void +init_boundary_buffer(boundary_info * , + int16_t height); + +void +free_boundary_buffer(boundary_info *); + +bool +gen_triangle_boundaries(int32_t xy[3][2], + boundary_info *, + int16_t width, + int16_t height); + +void +get_triangle_boundaries(uint16_t row_index, + int32_t * left, + int32_t * right, + const boundary_info *); + +#endif diff --git a/generator/pamtris/common.h b/generator/pamtris/common.h deleted file mode 100644 index eb9496fa..00000000 --- a/generator/pamtris/common.h +++ /dev/null @@ -1,437 +0,0 @@ -#include <netpbm/pam.h> -#include <netpbm/shhopt.h> -#include <netpbm/mallocvar.h> - -#include <stdbool.h> -#include <stdint.h> - -#define MAX_MAXVAL 65535 -#define MAX_NUM_ATTRIBS 20 -#define MAX_Z ((1 << 30) - 1) - -/*---------------------------------------------------------------------------- - Struct definitions -----------------------------------------------------------------------------*/ - - -typedef struct { -/*---------------------------------------------------------------------------- - This struct and the functions that manipulate variables of this type act - as a substitute for floating point computations. Here, whenever we need a - value with a fractional component, we represent it using two parts: 1. An - integer part, called the "quotient", and 2. A fractional part, which is - itself composed of a "remainder" (or "numerator") and a "divisor" (or - "denominator"). The fract struct provides storage for the quotient and the - remainder, but the divisor must be given separately (because it often - happens in this program that whenever we are dealing with one variable of - type fract, we are dealing with more of them at the same time, and they - all have the same divisor). - - To be more precise, the way we actually use variables of this type works - like this: We read integer values through standard input; When drawing - triangles, we need need to calculate differences between some pairs of - these input values and divide such differences by some other integer, - which is the above mentioned divisor. That result is then used to compute - successive interpolations between the two values for which we had - originally calculated the difference, and is therefore called the - "interpolation step". The values between which we wish to take successive - interpolations are called the "initial value" and the "final value". The - interpolation procedure works like this: First, we transform the initial - value into a fract variable by equating the quotient of that variable to - the initial value and assigning 0 to its remainder. Then, we successivelly - apply the interpolation step to that variable through successive calls to - step_up and/or multi_step_up until the quotient of the variable equals the - final value. Each application of step_up or multi_step_up yields a - particular linear interpolation between the initial and final values. - - If and only if a particular fract variable represents an interpolation - step, the "negative_flag" field indicates whether the step is negative - (i. e. negative_flag == true) or not (negative_flag == false). This is - necessary in order to make sure that variables are "stepped up" in the - appropriate direction, so to speak, as the field which stores the - remainder in any fract variable, "r", is always equal to or above 0, and - the quotient of a step may be 0, so the actual sign of the step value is - not always discoverable through a simple examination of the sign of the - quotient. On the other hand, if the variable does not represent an - interpolation step, the negative_flag is meaningless. ------------------------------------------------------------------------------*/ - int32_t q; /* Quotient */ - int32_t r: 31; /* Remainder */ - bool negative_flag: 1; -} fract; - - - -/* Each of the following structs has only one instance, which are created in - the main function. -*/ - -typedef struct { -/*---------------------------------------------------------------------------- - Information about the frame buffer and PAM output ------------------------------------------------------------------------------*/ - /* These fields are initialized once by reading the command line - arguments. "maxval" and "num_attribs" may be modified later - through "realloc_image_buffer". - */ - int32_t width; - int32_t height; - int32_t maxval; - int32_t num_attribs; - - /* The fields below must be initialized by "init_framebuffer" and - freed by "free_framebuffer", except for the tuple_type field in - "outpam" which is initialized once by reading the command line - arguments and may be modified later through "set_tupletype". - */ - struct { - uint16_t * buffer; - uint32_t bytes; - } img; /* Image buffer */ - - struct { - uint32_t * buffer; - uint32_t bytes; - } z; /* Z-buffer */ - - struct pam outpam; - - tuple * pamrow; -} framebuffer_info; - - - -typedef struct { -/*---------------------------------------------------------------------------- - Information about visible triangle rows' boundaries. Also see the - "boundary buffer functions" below. - - A "visible" triangle row is one which: - - 1. Corresponds to a frame buffer row whose index (from top to bottom) is - equal to or greater than 0 and smaller than the image height; and - - 2. Has at least some of its pixels between the frame buffer columns whose - index (from left to right) is equal to or greater than 0 and smaller - than the image width. ------------------------------------------------------------------------------*/ - int16_t start_scanline; - /* Index of the frame buffer scanline which contains the first visible - row of the current triangle, if there is any such row. If not, it - contains the value -1. - */ - - int16_t num_upper_rows; - /* The number of visible rows in the upper part of the triangle. The - upper part of a triangle is composed of all the rows starting from - the top vertex down to the middle vertex, but not including this - last one. - */ - - int16_t num_lower_rows; - /* The number of visible rows in the lower part of the triangle. The - lower part of a triangle is composed of all the rows from the - middle vertex to the bottom vertex -- all inclusive. - */ - - int16_t * buffer; - /* This is the "boundary buffer": a pointer to an array of int16_t's - where each consecutive pair of values indicates, in this order, the - columns of the left and right boundary pixels for a particular - visible triangle row. Those boundaries are inclusive on both sides - and may be outside the limits of the frame buffer. This field is - initialized and freed by the functions "init_boundary_buffer" and - "free_boundary_buffer", respectively. - */ -} boundary_info; - -typedef struct { -/*---------------------------------------------------------------------------- - Information necessary for the "process_next_command" function. It must be - initialized through "init_input_processor" and freed by - "free_input_processor". ------------------------------------------------------------------------------*/ - char * buffer; - size_t length; - uint64_t number; -} input_info; - -/*---------------------------------------------------------------------------- - Utility functions ------------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- - Generate the interpolation steps for a collection of initial and final - values. "begin" points to an array of initial values, "end" points to the - array of corresponding final values; each interpolation step is stored in - the appropriate position in the array pointed by "out"; "elements" indicates - the number of elements in each of the previously mentioned arrays and - "divisor" is the common value by which we want to divide the difference - between each element in the array pointed to by "end" and the corresponding - element in the array pointed to by "begin". After an execution of this - function, for each out[i], with 0 <= i < elements, the following will hold: - - 1. If divisor > 1: - out[i].q = (end[i] - begin[i]) / divisor - out[i].r = abs((end[i] - begin[i]) % divisor) - - 2. If divisor == 1 || divisor == 0: - out[i].q = end[i] - begin[i] - out[i].r = 0 ------------------------------------------------------------------------------*/ -void -gen_steps(const int32_t * begin, - const int32_t * end, - fract * out, - uint8_t elements, - int32_t divisor); - -/*---------------------------------------------------------------------------- - Apply interpolation steps (see above) to a collection of fract - variables (also see above) once. This is done by adding the - quotient of each step to the quotient of the corresponding variable - and the remainder of that step to the remainder of the variable. If the - remainder of the variable becomes equal to or larger than the - divisor, we increment the quotient of the variable if the negetive_flag - of the step is false, or decrement it if the negetive_flag is true, and - subtract the divisor from the remainder of the variable (in both cases). - - It *is* safe to pass a 0 divisor to this function. ------------------------------------------------------------------------------*/ -void -step_up(fract * vars, - const fract * steps, - uint8_t elements, - int32_t divisor); - -/*---------------------------------------------------------------------------- - Similar to step_up, but apply the interpolation step an arbitrary number - of times, instead of just once. - - It *is* also safe to pass a 0 divisor to this function. ------------------------------------------------------------------------------*/ -void -multi_step_up(fract * vars, - const fract * steps, - uint8_t elements, - int32_t times, - int32_t divisor); - -void -fract_to_int32_array(const fract * in, - int32_t * out, - uint8_t elements); - -void -int32_to_fract_array(const int32_t * in, - fract * out, - uint8_t elements); - -/*---------------------------------------------------------------------------- - Sort an index array of 3 elements. This function is used to sort vertices - with regard to relative row from top to bottom, but instead of sorting - an array of vertices with all their coordinates, we simply sort their - indices. Each element in the array pointed to by "index_array" should - contain one of the numbers 0, 1 or 2, and each one of them should be - different. "y_array" should point to an array containing the corresponding - Y coordinates (row) of each vertex and "x_array" should point to an array - containing the corresponding X coordinates (column) of each vertex. - - If the Y coordinates are all equal, the indices are sorted with regard to - relative X coordinate from left to right. If only the top two vertex have - the same Y coordinate, the array is sorted normally with regard to relative - Y coordinate, but the first two indices are then sorted with regard to - relative X coordinate. Finally, If only the bottom two vertex have the same - Y coordinate, the array is sorted normally with regard to relative Y - coordinate, but the last two indices are then sorted with regard to relative - X coordinate. ------------------------------------------------------------------------------*/ -void -sort3(uint8_t * index_array, - const int32_t * y_array, - const int32_t * x_array); - -/*---------------------------------------------------------------------------- - Frame buffer functions ------------------------------------------------------------------------------- - - Every drawing operation is applied on an internal "frame buffer", which is - simply an "image buffer" which represents the picture currently being drawn, - along with a "Z-Buffer" which contains the depth values for every pixel in - the image buffer. Once all desired drawing operations for a particular - picture are effected, a function is provided to print the current contents - of the image buffer as a PAM image on standard output. Another function is - provided to clear the contents of the frame buffer (i. e. set all image - samples and Z-Buffer entries to 0), with the option of only clearing either - the image buffer or the Z-Buffer individually. - - The Z-Buffer works as follows: Every pixel in the image buffer has a - corresponding entry in the Z-Buffer. Initially, every entry in the Z-Buffer - is set to 0. Every time we desire to plot a pixel at some particular - position in the frame buffer, the current value of the corresponding entry - in the Z-Buffer is compared against the the Z component of the incoming - pixel. If MAX_Z minus the value of the Z component of the incoming pixel is - equal to or greater than the current value of the corresponding entry in the - Z-Buffer, the frame buffer is changed as follows: - - 1. All the samples but the last of the corresponding position in the - image buffer are set to equal those of the incoming pixel. - - 2. The last sample, that is, the A-component of the corresponding position - in the image buffer is set to equal the maxval. - - 3. The corresponding entry in the Z-Buffer is set to equal MAX_Z minus the - value of the Z component of the incoming pixel. - - Otherwise, no changes are made on the frame buffer. ------------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- - Set the tuple type for the output PAM images given a string ("str") of 255 - characters or less. If the string has more than 255 characters, the function - returns 0. Otherwise, it returns 1. If NULL is given for the "str" argument, - the tuple type is set to a null string. This function is called during - program initialization and whenever a "r" command is executed. The second - argument must point to the tuple_type member of the "outpam" field in the - framebuffer_info struct. ------------------------------------------------------------------------------*/ -int -set_tupletype(const char * str, - char tupletype[256]); - -int -init_framebuffer(framebuffer_info *); - -void -free_framebuffer(framebuffer_info *); - -void -print_framebuffer(framebuffer_info *); - -void -clear_framebuffer(bool clear_image_buffer, - bool clear_z_buffer, - framebuffer_info *); - -/*---------------------------------------------------------------------------- - Reallocate the image buffer with a new maxval and depth, given the struct - with information about the framebuffer. The fields variables "maxval" and - "num_attribs". - - From the point this function is called onwards, new PAM images printed on - standard output will have the new maxval for the maxval and num_attribs + 1 - for the depth. - - This function does *not* check whether the new maxval and num_attribs are - within the proper allowed limits. That is done inside the input processing - function "process_next_command", which is the only function that calls this - one. - - If the function suceeds, the image buffer is left in cleared state. The - Z-Buffer, however, is not touched at all. - - If the new depth is equal to the previous one, no actual reallocation is - performed: only the global variable "maxval" is changed. But the image - buffer is nonetheless left in cleared state regardless. ------------------------------------------------------------------------------*/ -int -realloc_image_buffer(int32_t new_maxval, - int32_t new_num_attribs, - framebuffer_info *); - -/*---------------------------------------------------------------------------- - Draw a horizontal span of "length" pixels into the frame buffer, performing - the appropriate depth tests. "base" must equal the row of the frame buffer - where one desires to draw the span *times* the image width, plus the column - of the first pixel in the span. - - This function does not perform any kind of bounds checking. ------------------------------------------------------------------------------*/ -void draw_span(uint32_t base, - uint16_t length, - fract * attribs_start, - const fract * attribs_steps, - int32_t divisor, - framebuffer_info *); - - -/*---------------------------------------------------------------------------- - Boundary buffer functions ------------------------------------------------------------------------------- - New triangles are drawn one scanline at a time, and for every such scanline - we have left and right boundary columns within the frame buffer such that - the fraction of the triangle's area within that scanline is enclosed - between those two points (inclusive). Those coordinates may correspond to - columns outside the frame buffer's actual limits, in which case proper - post-processing should be made wherever such coordinates are used to - actually plot anything into the frame buffer. ------------------------------------------------------------------------------*/ - -void -init_boundary_buffer(boundary_info * , - int16_t height); - -void -free_boundary_buffer(boundary_info *); - -/*---------------------------------------------------------------------------- - Generate an entry in the boundary buffer for the boundaries of every - VISIBLE row of a particular triangle. In case there is no such row, - start_row is accordingly set to -1. The argument is a 3-element array - of pairs of int16_t's representing the coordinates of the vertices of - a triangle. Those vertices MUST be already sorted in order from the - uppermost to the lowermost vertex (which is what draw_triangle, the - only function which uses this one, does with the help of sort3). - - The return value indicates whether the middle vertex is to the left of the - line connecting the top vertex to the bottom vertex or not. ------------------------------------------------------------------------------*/ - -bool -gen_triangle_boundaries(int32_t xy[3][2], - boundary_info *, - int16_t width, - int16_t height); - -/*---------------------------------------------------------------------------- - Return the left and right boundaries for a given VISIBLE triangle row (the - row index is relative to the first visible row). These values may be out of - the horizontal limits of the frame buffer, which is necessary in order to - compute correct attribute interpolations. ------------------------------------------------------------------------------*/ -void -get_triangle_boundaries(uint16_t row_index, - int32_t * left, - int32_t * right, - const boundary_info *); - -/*---------------------------------------------------------------------------- - Triangle functions ------------------------------------------------------------------------------*/ - -void -draw_triangle(int32_t xy[3][2], - int32_t attribs[3][MAX_NUM_ATTRIBS + 1], - boundary_info *, - framebuffer_info *); - -/*---------------------------------------------------------------------------- - Input handling functions ------------------------------------------------------------------------------*/ - -void -init_input_processor(input_info *); - -void -free_input_processor(input_info *); - -/*---------------------------------------------------------------------------- - Doesn't necessarily process a command, just the next line of input, which - may be empty. Always returns 1, except when it cannot read any more lines of - input, an image buffer reallocation fails, or a "q" command is found in the - input -- in such cases it returns 0. ------------------------------------------------------------------------------*/ -int -process_next_command(input_info *, - boundary_info *, - framebuffer_info *); diff --git a/generator/pamtris/depend.mk b/generator/pamtris/depend.mk index 3b6df8e2..4660b87c 100644 --- a/generator/pamtris/depend.mk +++ b/generator/pamtris/depend.mk @@ -1,36 +1,25 @@ -triangle.o: triangle.c common.h importinc/netpbm/pam.h \ - importinc/netpbm/pm_config.h importinc/netpbm/pm.h \ - importinc/netpbm/pnm.h importinc/netpbm/ppm.h importinc/netpbm/pgm.h \ - importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h \ - importinc/netpbm/shhopt.h importinc/netpbm/mallocvar.h \ - importinc/netpbm/pm_config.h -framebuffer.o: framebuffer.c common.h importinc/netpbm/pam.h \ - importinc/netpbm/pm_config.h importinc/netpbm/pm.h \ - importinc/netpbm/pnm.h importinc/netpbm/ppm.h importinc/netpbm/pgm.h \ - importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h \ - importinc/netpbm/shhopt.h importinc/netpbm/mallocvar.h \ - importinc/netpbm/pm_config.h -boundaries.o: boundaries.c common.h importinc/netpbm/pam.h \ - importinc/netpbm/pm_config.h importinc/netpbm/pm.h \ - importinc/netpbm/pnm.h importinc/netpbm/ppm.h importinc/netpbm/pgm.h \ - importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h \ - importinc/netpbm/shhopt.h importinc/netpbm/mallocvar.h \ - importinc/netpbm/pm_config.h -pamtris.o: pamtris.c common.h importinc/netpbm/pam.h \ - importinc/netpbm/pm_config.h importinc/netpbm/pm.h \ - importinc/netpbm/pnm.h importinc/netpbm/ppm.h importinc/netpbm/pgm.h \ - importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h \ - importinc/netpbm/shhopt.h importinc/netpbm/mallocvar.h \ - importinc/netpbm/pm_config.h -input.o: input.c common.h importinc/netpbm/pam.h \ - importinc/netpbm/pm_config.h importinc/netpbm/pm.h \ - importinc/netpbm/pnm.h importinc/netpbm/ppm.h importinc/netpbm/pgm.h \ - importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h \ - importinc/netpbm/shhopt.h importinc/netpbm/mallocvar.h \ - importinc/netpbm/pm_config.h -utils.o: utils.c common.h importinc/netpbm/pam.h \ - importinc/netpbm/pm_config.h importinc/netpbm/pm.h \ - importinc/netpbm/pnm.h importinc/netpbm/ppm.h importinc/netpbm/pgm.h \ - importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h \ - importinc/netpbm/shhopt.h importinc/netpbm/mallocvar.h \ - importinc/netpbm/pm_config.h +triangle.o: triangle.c importinc/netpbm/mallocvar.h \ + importinc/netpbm/pm_config.h utils.h fract.h boundaries.h framebuffer.h \ + importinc/netpbm/pam.h importinc/netpbm/pm_config.h \ + importinc/netpbm/pm.h importinc/netpbm/pnm.h importinc/netpbm/ppm.h \ + importinc/netpbm/pgm.h importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h \ + triangle.h limits_pamtris.h +framebuffer.o: framebuffer.c utils.h fract.h limits_pamtris.h \ + framebuffer.h importinc/netpbm/pam.h importinc/netpbm/pm_config.h \ + importinc/netpbm/pm.h importinc/netpbm/pnm.h importinc/netpbm/ppm.h \ + importinc/netpbm/pgm.h importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h +boundaries.o: boundaries.c importinc/netpbm/mallocvar.h \ + importinc/netpbm/pm_config.h utils.h fract.h boundaries.h +pamtris.o: pamtris.c importinc/netpbm/mallocvar.h \ + importinc/netpbm/pm_config.h importinc/netpbm/shhopt.h \ + importinc/netpbm/pam.h importinc/netpbm/pm_config.h \ + importinc/netpbm/pm.h importinc/netpbm/pnm.h importinc/netpbm/ppm.h \ + importinc/netpbm/pgm.h importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h \ + limits_pamtris.h framebuffer.h fract.h boundaries.h input.h +input.o: input.c importinc/netpbm/mallocvar.h \ + importinc/netpbm/pm_config.h limits_pamtris.h framebuffer.h fract.h \ + importinc/netpbm/pam.h importinc/netpbm/pm_config.h \ + importinc/netpbm/pm.h importinc/netpbm/pnm.h importinc/netpbm/ppm.h \ + importinc/netpbm/pgm.h importinc/netpbm/pbm.h importinc/netpbm/ppmcmap.h \ + triangle.h input.h +utils.o: utils.c fract.h utils.h diff --git a/generator/pamtris/fract.h b/generator/pamtris/fract.h new file mode 100644 index 00000000..ff3c4402 --- /dev/null +++ b/generator/pamtris/fract.h @@ -0,0 +1,54 @@ +#ifndef FRACT_H_INCLUDED +#define FRACT_H_INCLUDED + +#include <stdbool.h> +#include <stdint.h> + + +typedef struct { +/*---------------------------------------------------------------------------- + This struct and the functions that manipulate variables of this type act + as a substitute for floating point computations. Here, whenever we need a + value with a fractional component, we represent it using two parts: 1. An + integer part, called the "quotient", and 2. A fractional part, which is + itself composed of a "remainder" (or "numerator") and a "divisor" (or + "denominator"). The fract struct provides storage for the quotient and the + remainder, but the divisor must be given separately (because it often + happens in this program that whenever we are dealing with one variable of + type fract, we are dealing with more of them at the same time, and they + all have the same divisor). + + To be more precise, the way we actually use variables of this type works + like this: We read integer values through standard input; When drawing + triangles, we need need to calculate differences between some pairs of + these input values and divide such differences by some other integer, + which is the above mentioned divisor. That result is then used to compute + successive interpolations between the two values for which we had + originally calculated the difference, and is therefore called the + "interpolation step". The values between which we wish to take successive + interpolations are called the "initial value" and the "final value". The + interpolation procedure works like this: First, we transform the initial + value into a fract variable by equating the quotient of that variable to + the initial value and assigning 0 to its remainder. Then, we successivelly + apply the interpolation step to that variable through successive calls to + step_up and/or multi_step_up until the quotient of the variable equals the + final value. Each application of step_up or multi_step_up yields a + particular linear interpolation between the initial and final values. + + If and only if a particular fract variable represents an interpolation + step, the "negative_flag" field indicates whether the step is negative + (i. e. negative_flag == true) or not (negative_flag == false). This is + necessary in order to make sure that variables are "stepped up" in the + appropriate direction, so to speak, as the field which stores the + remainder in any fract variable, "r", is always equal to or above 0, and + the quotient of a step may be 0, so the actual sign of the step value is + not always discoverable through a simple examination of the sign of the + quotient. On the other hand, if the variable does not represent an + interpolation step, the negative_flag is meaningless. +-----------------------------------------------------------------------------*/ + int32_t q; /* Quotient */ + int32_t r: 31; /* Remainder */ + bool negative_flag: 1; +} fract; + +#endif diff --git a/generator/pamtris/framebuffer.c b/generator/pamtris/framebuffer.c index cbb1e4a8..01a66bea 100644 --- a/generator/pamtris/framebuffer.c +++ b/generator/pamtris/framebuffer.c @@ -1,14 +1,63 @@ +/*============================================================================= + framebuffer.c +=============================================================================== + Frame buffer functions + + Every drawing operation is applied on an internal "frame buffer", which is + simply an "image buffer" which represents the picture currently being drawn, + along with a "Z-Buffer" which contains the depth values for every pixel in + the image buffer. Once all desired drawing operations for a particular + picture are effected, a function is provided to print the current contents + of the image buffer as a PAM image on standard output. Another function is + provided to clear the contents of the frame buffer (i. e. set all image + samples and Z-Buffer entries to 0), with the option of only clearing either + the image buffer or the Z-Buffer individually. + + The Z-Buffer works as follows: Every pixel in the image buffer has a + corresponding entry in the Z-Buffer. Initially, every entry in the Z-Buffer + is set to 0. Every time we desire to plot a pixel at some particular + position in the frame buffer, the current value of the corresponding entry + in the Z-Buffer is compared against the the Z component of the incoming + pixel. If MAX_Z minus the value of the Z component of the incoming pixel is + equal to or greater than the current value of the corresponding entry in the + Z-Buffer, the frame buffer is changed as follows: + + 1. All the samples but the last of the corresponding position in the + image buffer are set to equal those of the incoming pixel. + + 2. The last sample, that is, the A-component of the corresponding position + in the image buffer is set to equal the maxval. + + 3. The corresponding entry in the Z-Buffer is set to equal MAX_Z minus the + value of the Z component of the incoming pixel. + + Otherwise, no changes are made on the frame buffer. +=============================================================================*/ +#include <stdbool.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> -#include "common.h" +#include "utils.h" +#include "fract.h" +#include "limits_pamtris.h" + +#include "framebuffer.h" int set_tupletype(const char * str, char tupletype[256]) { - +/*---------------------------------------------------------------------------- + Set the tuple type for the output PAM images given a string ("str") of 255 + characters or less. If the string has more than 255 characters, the function + returns 0. Otherwise, it returns 1. If NULL is given for the "str" argument, + the tuple type is set to a null string. This function is called during + program initialization and whenever a "r" command is executed. The second + argument must point to the tuple_type member of the "outpam" field in the + framebuffer_info struct. +-----------------------------------------------------------------------------*/ if (str == NULL) { memset(tupletype, 0, 256); @@ -101,7 +150,27 @@ int realloc_image_buffer(int32_t new_maxval, int32_t new_num_attribs, framebuffer_info * fbi) { - +/*---------------------------------------------------------------------------- + Reallocate the image buffer with a new maxval and depth, given the struct + with information about the framebuffer. The fields variables "maxval" and + "num_attribs". + + From the point this function is called onwards, new PAM images printed on + standard output will have the new maxval for the maxval and num_attribs + 1 + for the depth. + + This function does *not* check whether the new maxval and num_attribs are + within the proper allowed limits. That is done inside the input processing + function "process_next_command", which is the only function that calls this + one. + + If the function suceeds, the image buffer is left in cleared state. The + Z-Buffer, however, is not touched at all. + + If the new depth is equal to the previous one, no actual reallocation is + performed: only the global variable "maxval" is changed. But the image + buffer is nonetheless left in cleared state regardless. +-----------------------------------------------------------------------------*/ uint8_t num_planes = fbi->num_attribs + 1; pnm_freepamrow(fbi->pamrow); @@ -209,7 +278,14 @@ draw_span(uint32_t base, const fract * attribs_steps, int32_t div, framebuffer_info * fbi) { - +/*---------------------------------------------------------------------------- + Draw a horizontal span of "length" pixels into the frame buffer, performing + the appropriate depth tests. "base" must equal the row of the frame buffer + where one desires to draw the span *times* the image width, plus the column + of the first pixel in the span. + + This function does not perform any kind of bounds checking. +-----------------------------------------------------------------------------*/ uint8_t num_planes = fbi->num_attribs + 1; unsigned int i; diff --git a/generator/pamtris/framebuffer.h b/generator/pamtris/framebuffer.h new file mode 100644 index 00000000..9b3d4dcf --- /dev/null +++ b/generator/pamtris/framebuffer.h @@ -0,0 +1,75 @@ +#ifndef FRAMEBUFFER_H_INCLUDED +#define FRAMEBUFFER_H_INCLUDED + +#include <stdint.h> +#include <stdbool.h> +#include "fract.h" +#include "netpbm/pam.h" + +typedef struct framebuffer_info { +/*---------------------------------------------------------------------------- + Information about the frame buffer and PAM output +-----------------------------------------------------------------------------*/ + /* These fields are initialized once by reading the command line + arguments. "maxval" and "num_attribs" may be modified later + through "realloc_image_buffer". + */ + int32_t width; + int32_t height; + int32_t maxval; + int32_t num_attribs; + + /* The fields below must be initialized by "init_framebuffer" and + freed by "free_framebuffer", except for the tuple_type field in + "outpam" which is initialized once by reading the command line + arguments and may be modified later through "set_tupletype". + */ + struct { + uint16_t * buffer; + uint32_t bytes; + } img; /* Image buffer */ + + struct { + uint32_t * buffer; + uint32_t bytes; + } z; /* Z-buffer */ + + struct pam outpam; + + tuple * pamrow; +} framebuffer_info; + + + +int +set_tupletype(const char * str, + char tupletype[256]); + +int +init_framebuffer(framebuffer_info *); + +void +free_framebuffer(framebuffer_info *); + +void +print_framebuffer(framebuffer_info *); + +void +clear_framebuffer(bool clear_image_buffer, + bool clear_z_buffer, + framebuffer_info *); + +int +realloc_image_buffer(int32_t new_maxval, + int32_t new_num_attribs, + framebuffer_info *); + +void +draw_span(uint32_t base, + uint16_t length, + fract * attribs_start, + const fract * attribs_steps, + int32_t divisor, + framebuffer_info *); + +#endif diff --git a/generator/pamtris/input.c b/generator/pamtris/input.c index 0daa623e..3529c16d 100644 --- a/generator/pamtris/input.c +++ b/generator/pamtris/input.c @@ -1,8 +1,21 @@ +/*============================================================================= + input.c +=============================================================================== + Input handling functions +=============================================================================*/ +#include <stdbool.h> +#include <stdint.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> -#include "common.h" +#include "netpbm/mallocvar.h" + +#include "limits_pamtris.h" +#include "framebuffer.h" +#include "triangle.h" + +#include "input.h" #define MAX_COORD 32767 #define MIN_COORD -MAX_COORD @@ -186,10 +199,15 @@ remove_comments(char * str) { int -process_next_command(input_info * line, - boundary_info * bi, - framebuffer_info * fbi) { - +process_next_command(input_info * line, + struct boundary_info * bi, + framebuffer_info * fbi) { +/*---------------------------------------------------------------------------- + Doesn't necessarily process a command, just the next line of input, which + may be empty. Always returns 1, except when it cannot read any more lines of + input, an image buffer reallocation fails, or a "q" command is found in the + input -- in such cases it returns 0. +-----------------------------------------------------------------------------*/ static state_info state; token nt; @@ -547,7 +565,7 @@ process_next_command(input_info * line, break; } - if (i_args[0] < 1 || i_args[0] > MAX_MAXVAL) { + if (i_args[0] < 1 || i_args[0] > PAM_OVERALL_MAXVAL) { pm_errormsg("error: invalid new maxval: line %lu.", line->number); diff --git a/generator/pamtris/input.h b/generator/pamtris/input.h new file mode 100644 index 00000000..867cca02 --- /dev/null +++ b/generator/pamtris/input.h @@ -0,0 +1,31 @@ +#ifndef INPUT_H_INCLUDED +#define INPUT_H_INCLUDED + +#include <stdint.h> + +struct boundary_info; +struct framebuffer_info; + +typedef struct input_info { +/*---------------------------------------------------------------------------- + Information necessary for the "process_next_command" function. It must be + initialized through "init_input_processor" and freed by + "free_input_processor". +-----------------------------------------------------------------------------*/ + char * buffer; + size_t length; + uint64_t number; +} input_info; + +void +init_input_processor(input_info *); + +void +free_input_processor(input_info *); + +int +process_next_command(input_info *, + struct boundary_info *, + struct framebuffer_info *); + +#endif diff --git a/generator/pamtris/limits_pamtris.h b/generator/pamtris/limits_pamtris.h new file mode 100644 index 00000000..dcf1f1e6 --- /dev/null +++ b/generator/pamtris/limits_pamtris.h @@ -0,0 +1,7 @@ +#ifndef LIMITS_H_INCLUDED +#define LIMITS_H_INCLUDED + +#define MAX_NUM_ATTRIBS 20 +#define MAX_Z ((1 << 30) - 1) + +#endif diff --git a/generator/pamtris/pamtris.c b/generator/pamtris/pamtris.c index 2ef57891..3237b009 100644 --- a/generator/pamtris/pamtris.c +++ b/generator/pamtris/pamtris.c @@ -1,6 +1,15 @@ +#include <stdbool.h> +#include <stdint.h> #include <stdlib.h> -#include "common.h" +#include "netpbm/mallocvar.h" +#include "netpbm/shhopt.h" +#include "netpbm/pam.h" + +#include "limits_pamtris.h" +#include "framebuffer.h" +#include "boundaries.h" +#include "input.h" #define MAX_METRICS 8192 @@ -62,7 +71,7 @@ parse_command_line ( } if (maxval_spec) { - if (*maxval < 1 || *maxval > MAX_MAXVAL) { + if (*maxval < 1 || *maxval > PAM_OVERALL_MAXVAL) { pm_errormsg("invalid maxval."); return 0; diff --git a/generator/pamtris/triangle.c b/generator/pamtris/triangle.c index 570cff5f..eb6b7a00 100644 --- a/generator/pamtris/triangle.c +++ b/generator/pamtris/triangle.c @@ -1,9 +1,20 @@ +/*============================================================================= + triangle.c +=============================================================================== + Triangle functions +=============================================================================*/ #include <stdlib.h> #include <string.h> -#include "common.h" +#include "netpbm/mallocvar.h" +#include "utils.h" +#include "fract.h" +#include "limits.h" +#include "boundaries.h" +#include "framebuffer.h" +#include "triangle.h" static void draw_partial_triangle( diff --git a/generator/pamtris/triangle.h b/generator/pamtris/triangle.h new file mode 100644 index 00000000..07e6d065 --- /dev/null +++ b/generator/pamtris/triangle.h @@ -0,0 +1,17 @@ +#ifndef TRIANGLE_H_INCLUDED +#define TRIANGLE_H_INCLUDED + +#include <stdint.h> + +#include "limits_pamtris.h" + +struct boundary_info; +struct framebuffer_info; + +void +draw_triangle(int32_t xy[3][2], + int32_t attribs[3][MAX_NUM_ATTRIBS + 1], + struct boundary_info *, + struct framebuffer_info *); + +#endif diff --git a/generator/pamtris/utils.c b/generator/pamtris/utils.c index 550cc41d..1ef7283c 100644 --- a/generator/pamtris/utils.c +++ b/generator/pamtris/utils.c @@ -1,13 +1,35 @@ +/*============================================================================= + utils.c +=============================================================================== + Utility functions +=============================================================================*/ + #include <stdlib.h> +#include <stdint.h> + +#include "fract.h" + +#include "utils.h" + -#include "common.h" void step_up(fract * vars, const fract * steps, uint8_t elements, int32_t div) { - +/*---------------------------------------------------------------------------- + Apply interpolation steps (see above) to a collection of fract + variables (also see above) once. This is done by adding the + quotient of each step to the quotient of the corresponding variable + and the remainder of that step to the remainder of the variable. If the + remainder of the variable becomes equal to or larger than the + divisor, we increment the quotient of the variable if the negetive_flag + of the step is false, or decrement it if the negetive_flag is true, and + subtract the divisor from the remainder of the variable (in both cases). + + It *is* safe to pass a 0 divisor to this function. +-----------------------------------------------------------------------------*/ unsigned int i; for (i = 0; i < elements; ++i) { @@ -35,7 +57,12 @@ multi_step_up(fract * vars, uint8_t elements, int32_t times, int32_t div) { +/*---------------------------------------------------------------------------- + Similar to step_up, but apply the interpolation step an arbitrary number + of times, instead of just once. + It *is* also safe to pass a 0 divisor to this function. +-----------------------------------------------------------------------------*/ unsigned int i; for (i = 0; i < elements; i++) { @@ -61,7 +88,25 @@ void gen_steps(const int32_t * begin, const int32_t * end, fract * out, uint8_t elements, int32_t div) { - +/*---------------------------------------------------------------------------- + Generate the interpolation steps for a collection of initial and final + values. "begin" points to an array of initial values, "end" points to the + array of corresponding final values; each interpolation step is stored in + the appropriate position in the array pointed by "out"; "elements" indicates + the number of elements in each of the previously mentioned arrays and + "divisor" is the common value by which we want to divide the difference + between each element in the array pointed to by "end" and the corresponding + element in the array pointed to by "begin". After an execution of this + function, for each out[i], with 0 <= i < elements, the following will hold: + + 1. If divisor > 1: + out[i].q = (end[i] - begin[i]) / divisor + out[i].r = abs((end[i] - begin[i]) % divisor) + + 2. If divisor == 1 || divisor == 0: + out[i].q = end[i] - begin[i] + out[i].r = 0 +-----------------------------------------------------------------------------*/ if (div > 1) { unsigned int i; @@ -133,7 +178,25 @@ void sort3(uint8_t * index_array, const int32_t * y_array, const int32_t * x_array) { - +/*---------------------------------------------------------------------------- + Sort an index array of 3 elements. This function is used to sort vertices + with regard to relative row from top to bottom, but instead of sorting + an array of vertices with all their coordinates, we simply sort their + indices. Each element in the array pointed to by "index_array" should + contain one of the numbers 0, 1 or 2, and each one of them should be + different. "y_array" should point to an array containing the corresponding + Y coordinates (row) of each vertex and "x_array" should point to an array + containing the corresponding X coordinates (column) of each vertex. + + If the Y coordinates are all equal, the indices are sorted with regard to + relative X coordinate from left to right. If only the top two vertex have + the same Y coordinate, the array is sorted normally with regard to relative + Y coordinate, but the first two indices are then sorted with regard to + relative X coordinate. Finally, If only the bottom two vertex have the same + Y coordinate, the array is sorted normally with regard to relative Y + coordinate, but the last two indices are then sorted with regard to relative + X coordinate. +-----------------------------------------------------------------------------*/ uint8_t * ia = index_array; const int32_t * ya = y_array; const int32_t * xa = x_array; diff --git a/generator/pamtris/utils.h b/generator/pamtris/utils.h new file mode 100644 index 00000000..8b945acd --- /dev/null +++ b/generator/pamtris/utils.h @@ -0,0 +1,41 @@ +#ifndef UTIL_H_INCLUDED +#define UTIL_H_INCLUDED + +#include "fract.h" + +void +gen_steps(const int32_t * begin, + const int32_t * end, + fract * out, + uint8_t elements, + int32_t divisor); + +void +step_up(fract * vars, + const fract * steps, + uint8_t elements, + int32_t divisor); + +void +multi_step_up(fract * vars, + const fract * steps, + uint8_t elements, + int32_t times, + int32_t divisor); + +void +fract_to_int32_array(const fract * in, + int32_t * out, + uint8_t elements); + +void +int32_to_fract_array(const int32_t * in, + fract * out, + uint8_t elements); + +void +sort3(uint8_t * index_array, + const int32_t * y_array, + const int32_t * x_array); + +#endif |