Practical Programming David Bouchet
Practical Work #3

Arrays and SDL

Submission

Due Date

By Friday 26 October 2018 23:42

Directory Hierarchy

Create your git repository (replace john.smith by your own login).

                
                    $ git clone git@git.cri.epita.net:p/2022-spe-tp/tp03-john.smith
                
            

It must contain the following files and directories:

Create an AUTHORS file that contains the following information.

AUTHORS
                
                    First Name
                    Family Name
                    Login
                    Email Address
                
            

For instance:

AUTHORS
                
                    John
                    Smith
                    john.smith
                    john.smith@epita.fr
                
            

Be careful, if you do not follow all the given instructions, no point will be given to your answers.

Basic Array Manipulations

Provided Code

Two helper files are provided. They are common to all exercises. Other specific files will be given in due time.

The first provided file is a header, which contains some useful functions for testing.

tests_tools.h
                
                    /* Tools for testing array functions */
                    
                    # ifndef EPITA_IP_ARRAY_TESTS_TOOLS_H_
                    # define EPITA_IP_ARRAY_TESTS_TOOLS_H_
                    
                    /*
                     * Needed in order to use some POSIX functions
                     * see feature_test_macros(7)
                     */
                    # define _XOPEN_SOURCE 500
                    
                    # include <stdio.h>
                    # include <stdlib.h>
                    
                    /*
                     * helper functions (array fill, display ... )
                     * all functions are statically inlined, no links dependencies
                     */
                    
                    /*
                     * array_random_fill(array, len, maxval): fill array with random values
                     * maxval is the maximum random value
                     */
                    static inline
                    void array_random_fill(int array[], size_t len, int maxval)
                    {
                        for (size_t i = 0; i < len; ++i)
                            array[i] = random() % maxval;
                    }
                    
                    /*
                     * array_sorted_fill(array, len, step): fill array with sorted value
                     * step is the difference between values
                     */
                    static inline
                    void array_sorted_fill(int array[], size_t len, int step)
                    {
                        int cur = 0;
                        for (size_t i = 0; i < len; ++i, cur += step)
                            array[i] = cur;
                    }
                    
                    /*
                     * array_reverse_sorted_fill(array, len, step): fill array with values in
                     * reverse order
                     * step is the difference between values
                     */
                    static inline
                    void array_reverse_sorted_fill(int array[], size_t len, int step)
                    {
                        int cur = (len - 1) * step;
                        for (size_t i = 0; i < len; ++i, cur -= step)
                            array[i] = cur;
                    }
                    
                    /*
                     * int_len(int x): number of decimal digit
                     */
                    static inline
                    int int_len(int x)
                    {
                        int len = 0;
                        for (; x > 0; x /= 10)
                            len += 1;
                        return len;
                    }
                    
                    /*
                     * array_print(array, len): print the array
                     */
                    static inline
                    void array_print(int array[], size_t len, int maxval)
                    {
                        int line = 0;
                        int intlen = int_len(maxval);
                    
                        for (size_t i = 0; i < len; ++i)
                        {
                            if (line > 72)
                            {
                                printf("|\n");
                                line = 0;
                            }
                    
                            line += printf("| %*d ", intlen, array[i]);
                        }
                    
                        printf("|\n");
                    }
                    
                    #define check(C__) ((C__) ? "\x1b[44mOK\x1b[0m" : "\x1b[41mKO\x1b[0m")
                    
                    # endif /* EPITA_IP_ARRAY_TESTS_TOOLS_H_ */
                
            

The second provided file is a simple Makefile.

Makefile
                
# Simple Makefile
 
# Compilers vars
CC=gcc
CPPFLAGS= -MMD
CFLAGS= -Wall -Wextra -std=c99 -O2
LDFLAGS=
LDLIBS=
 
SRC= array_min_max.c array_searching.c array_sorting.c
DEP= ${SRC:.c=.d}
PRG= ${SRC:.c=}
 
all: ${PRG}
 
-include ${DEP}
 
clean:
	rm -f *.o
	rm -f ${DEP}
	rm -f ${PRG}
 
# END Makefile
                
            

Minimal and Maximal Values

In this section, you will implement the four following functions:

                
                    int array_min(int array[], size_t len);
                    int array_max(int array[], size_t len);
                    size_t array_min_index(int array[], size_t len);
                    size_t array_max_index(int array[], size_t len);
                
            

Complete the following array_min_max.c file (replace only the TODO comments by your own code). Some tests are also provided.

array_min_max.c
                
                    /* array_min_max.c: min and max searching */
                    
                    # define _XOPEN_SOURCE 500
                    
                    # include <assert.h>
                    # include <err.h>
                    # include <stdio.h>
                    # include <stdlib.h>
                    
                    # include "tests_tools.h"
                    
                    # define MAXVAL 100
                    # define STEP 10
                    
                    /*
                     * In all following functions parameters array and len are defined as:
                     * array: an integer array
                     * len: the length of the array, must be greater than 0
                     */
                    
                    /*
                     * min and max value
                     */
                    
                    /*
                     * array_min(array, len): returns min value of array
                     */
                    int array_min(int array[], size_t len)
                    {
                        // TODO
                    }
                    
                    /*
                     * array_max(array, len): returns max value of array
                     */
                    int array_max(int array[], size_t len)
                    {
                        // TODO
                    }
                    
                    /*
                     * min and max index
                     */
                    
                    /*
                     * array_min_index(array, len): returns the index of the min value of array
                     */
                    size_t array_min_index(int array[], size_t len)
                    {
                        // TODO
                    }
                    
                    /*
                     * array_max_index(array, len): returns the index of the max value of array
                     */
                    size_t array_max_index(int array[], size_t len)
                    {
                        // TODO
                    }
                    
                    /*
                     * Tests
                     */
                    
                    /*
                     * Test functions
                     */
                    
                    /*
                     * min value tests
                     */
                    void test_min(int array[], size_t len)
                    {
                        int min;
                        printf("*** Test min value search ***\n");
                    
                        printf("**** Sorted array ****\n");
                        array_sorted_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        min = array_min(array, len);
                        printf("  array_min: %d\t(should be %d)\n", min, array[0]);
                    
                        printf("**** Reverse sorted array ****\n");
                        array_reverse_sorted_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        min = array_min(array, len);
                        printf("  array_min: %d\t(should be %d)\n", min, array[len - 1]);
                    
                        printf("**** Random array ****\n");
                        array_random_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        min = array_min(array, len);
                        printf("  array_min: %d\n", min);
                    }
                    
                    /*
                     * max value tests
                     */
                    void test_max(int array[], size_t len)
                    {
                        int max;
                        printf("*** Test max value search ***\n");
                    
                        printf("**** Sorted array ****\n");
                        array_sorted_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        max = array_max(array, len);
                        printf("  array_max: %d\t(should be %d)\n", max, array[len - 1]);
                    
                        printf("**** Reverse sorted array ****\n");
                        array_reverse_sorted_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        max = array_max(array, len);
                        printf("  array_max: %d\t(should be %d)\n", max, array[0]);
                    
                        printf("**** Random array ****\n");
                        array_random_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        max = array_max(array, len);
                        printf("  array_max: %d\n", max);
                    }
                    
                    /*
                     * min index test
                     */
                    void test_min_index(int array[], size_t len)
                    {
                        size_t min;
                        printf("*** Test min value index search ***\n");
                    
                        printf("**** Sorted array ****\n");
                        array_sorted_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        min = array_min_index(array, len);
                        printf("  array_min_index: array[%zu] = %d\n", min, array[min]);
                    
                        printf("**** Reverse sorted array ****\n");
                        array_reverse_sorted_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        min = array_min_index(array, len);
                        printf("  array_min_index: array[%zu] = %d\n", min, array[min]);
                    
                        printf("**** Random array ****\n");
                        array_random_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        min = array_min_index(array, len);
                        printf("  array_min_index: array[%zu] = %d\n", min, array[min]);
                    }
                    
                    /*
                     * max index test
                     */
                    void test_max_index(int array[], size_t len)
                    {
                        size_t max;
                        printf("*** Test max value index search ***\n");
                    
                        printf("**** Sorted array ****\n");
                        array_sorted_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        max = array_max_index(array, len);
                        printf("  array_max_index: array[%zu] = %d\n", max, array[max]);
                    
                        printf("**** Reverse sorted array ****\n");
                        array_reverse_sorted_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        max = array_max_index(array, len);
                        printf("  array_max_index: array[%zu] = %d\n", max, array[max]);
                    
                        printf("**** Random array ****\n");
                        array_random_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        max = array_max_index(array, len);
                        printf("  array_max_index: array[%zu] = %d\n", max, array[max]);
                    }
                    
                    /*
                     * main
                     */
                    int main(int argc, char *argv[])
                    {
                        size_t len;
                        if (argc < 2)
                            errx(1, "must provide array length");
                        len = strtoul(argv[1], NULL, 10);
                        int *array = calloc(len, sizeof (int));
                    
                        test_min(array, len);
                        printf("\n");
                    
                        test_max(array, len);
                        printf("\n");
                    
                        test_min_index(array, len);
                        printf("\n");
                    
                        test_max_index(array, len);
                        printf("\n");
                    
                        free(array);
                        return 0;
                    }
                
            

Finally, you can compile and test your code with the following commands:

                
                    $ make array_min_max 
                    gc
                
                
                    c -Wall -Wextra -std=c99 -O2 -MMD   array_min_max.c tests_tools.h   -o array_min_max
                    $ ./array_min_max 10
                    # ...snip...
                
            

Searching

In this section, you will implement the two following functions:

                
                    size_t array_find(int array[], size_t len, int x);
                    size_t array_bin_search(int array[], size_t len, int x);
                
            

The binary search algorithm is as follows (you should already know it):

                
                    bin_search(array, left, right, x):
                        if left == right:
                            return right
                        mid = left + (right - left) / 2
                        if array[mid] == x:
                            return mid
                        if x < array[mid]:
                            return bin_search(array, left, mid, x)
                        else:
                            return bin_search(array, mid + 1, right, x)
                
            

Of course, you can turn it into a loop. Note also that if x is not in the array, the binary search should return the expected position of x, that is, where x should be inserted if we want to preserve the order of the sorted array.

Complete the following array_searching.c file (replace only the TODO comments by your own code). Some tests are also provided.

array_searching.c
                
                    /* searching in array */
                    
                    # define _XOPEN_SOURCE 500
                    
                    # include <assert.h>
                    # include <err.h>
                    # include <stdio.h>
                    # include <stdlib.h>
                    # include <time.h>
                    
                    # include "tests_tools.h"
                    
                    # define MAXVAL 100
                    # define STEP 10
                    
                    /*
                     * In all following functions parameters array and len are defined as:
                     * array: an integer array
                     * len: the length of the array, must be greater than 0
                     */
                    
                    /*
                     * searching for value
                     */
                    
                    /*
                     * array_find(array, len, x): returns the position of x in array or len if not
                     * present
                     */
                    size_t array_find(int array[], size_t len, int x)
                    {
                        // TODO
                    }
                    
                    /*
                     * array_bin_search(array, len, x): search in a sorted array using binary search
                     * returns the position of x, or the expected position of x if not present
                     */
                    size_t array_bin_search(int array[], size_t len, int x)
                    {
                        // TODO
                    }
                    
                    /*
                     * Tests
                     */
                    
                    int array_random_sorted_fill(int array[], size_t len, int maxstep)
                    {
                        int cur = 0;
                        for (size_t i = 0; i < len; ++i)
                        {
                            int step = 1 + random() % maxstep;
                            cur += step;
                            array[i] = cur;
                        }
                        return cur;
                    }
                    
                    typedef size_t (*search_fun)(int *, size_t, int);
                    
                    static inline
                    void search_help(search_fun fun, int array[], size_t len, int x)
                    {
                        printf("  searching %d: ", x);
                        size_t i = fun(array, len, x);
                        if (i < len)
                            printf("array[%zu] = %d\n", i, array[i]);
                        else
                            printf("not found (%zu)\n", i);
                    }
                    
                    static
                    void test_search(int array[], size_t len)
                    {
                        int x;
                    
                        printf("*** Test value search ***\n");
                        printf("**** Sorted array ****\n");
                        array_sorted_fill(array, len, STEP);
                        array_print(array, len, (len - 1) * STEP);
                        x = array[0];
                        search_help(array_find, array, len, x);
                        x = array[len - 1];
                        search_help(array_find, array, len, x);
                        x = array[random() % len];
                        search_help(array_find, array, len, x);
                        x = len * STEP;
                        search_help(array_find, array, len, x);
                    
                        printf("**** Reverse sorted array ****\n");
                        array_reverse_sorted_fill(array, len, STEP);
                        array_print(array, len, (len - 1) * STEP);
                        x = array[0];
                        search_help(array_find, array, len, x);
                        x = array[len - 1];
                        search_help(array_find, array, len, x);
                        x = array[random() % len];
                        search_help(array_find, array, len, x);
                        x = len * STEP;
                        search_help(array_find, array, len, x);
                    
                        printf("**** Random array ****\n");
                        array_random_fill(array, len, MAXVAL);
                        array_print(array, len, MAXVAL);
                        x = array[0];
                        search_help(array_find, array, len, x);
                        x = array[len - 1];
                        search_help(array_find, array, len, x);
                        x = array[random() % len];
                        search_help(array_find, array, len, x);
                        x = random() % (MAXVAL * 2);
                        search_help(array_find, array, len, x);
                    }
                    
                    static
                    void test_bin_search(int array[], size_t len)
                    {
                        int x;
                    
                        printf("*** Test value binary search ***\n");
                    
                        printf("  founded index may not contain searched value\n");
                    
                        printf("**** Basic sorted array ****\n");
                        array_sorted_fill(array, len, STEP);
                        array_print(array, len, (len - 1) * STEP);
                        x = array[0];
                        search_help(array_bin_search, array, len, x);
                        x = array[len - 1];
                        search_help(array_bin_search, array, len, x);
                        x = array[random() % len];
                        search_help(array_bin_search, array, len, x);
                        x = len * STEP;
                        search_help(array_bin_search, array, len, x);
                    
                        printf("**** Basic sorted array ****\n");
                        int maxval = array_random_sorted_fill(array, len, STEP);
                        array_print(array, len, maxval);
                        x = array[0];
                        search_help(array_bin_search, array, len, x);
                        x = array[len - 1];
                        search_help(array_bin_search, array, len, x);
                        x = array[random() % len];
                        search_help(array_bin_search, array, len, x);
                        x = random() % (maxval * 2);
                        search_help(array_bin_search, array, len, x);
                    }
                    
                    /*
                     * main
                     */
                    int main(int argc, char *argv[])
                    {
                        srandom(time(NULL));
                    
                        size_t len;
                        if (argc < 2)
                            errx(1, "must provide array length");
                        len = strtoul(argv[1], NULL, 10);
                        int *array = calloc(len, sizeof (int));
                    
                        test_search(array, len);
                        printf("\n");
                    
                        test_bin_search(array, len);
                        printf("\n");
                    
                        free(array);
                        return 0;
                    }
                
            

Finally, you can compile and test your code with the following commands:

                
                    $ make array_searching
                    gc
                
                
                    c -Wall -Wextra -std=c99 -O2 -MMD   array_searching.c tests_tools.h   -o array_searching
                    $ ./array_searching 10
                    # ...snip...
                
            

Sorting

In this section, you will implement a selection sort algorithm:

                
                    select_sort(array, len):
                        for i in range(len):
                            # find min index in array between i and len
                            min = array_min(array[i:len])
                            swap(array[i], array[min])
                
            

As you can see, we need a function that finds the index of the minimal value in an array (we've already done it!) and a function for swapping array cells. We also want a function that checks if an array is sorted (for tests). For the index of the minimal value, you are free to reuse your code (you can call your function shifted by i with array_min_index(array+i, len-i) but beware of shifting the resulting index by i again) or write a specific version or simply include the code in the sort function.

Therefore, you have to write the three following functions:

                
                    int array_is_sorted(int array[], size_t len);
                    void array_swap(int array[], size_t i, size_t j);
                    void array_select_sort(int array[], size_t len);
                
            

To do so, complete the following array_sorting.c file (replace only the TODO comments by your own code). Some tests are also provided.

array_sorting.c
                
                    /* array_sorting.c : sorting arrays */
                    
                    # define _XOPEN_SOURCE 500
                    
                    # include <assert.h>
                    # include <err.h>
                    # include <stdio.h>
                    # include <stdlib.h>
                    # include <time.h>
                    
                    # include "tests_tools.h"
                    
                    # define MAXVAL 100
                    # define STEP 10
                    
                    /*
                     * In all following functions parameters array and len are defined as:
                     * array: an integer array
                     * len: the length of the array, must be greater than 0
                     */
                    
                    /* tools for sorting */
                    
                    /*
                     * array_is_sorted(array, len): returns true if array is sorted in increasing
                     * order
                     */
                    int array_is_sorted(int array[], size_t len)
                    {
                        // TODO
                    }
                    
                    /*
                     * array_swap(array, i, j): swap cell value at position i and j
                     */
                    void array_swap(int array[], size_t i, size_t j)
                    {
                        // TODO
                    }
                    
                    /* Selection sort */
                    
                    /*
                     * array_select_sort(array, len): sort array using select sort
                     */
                    void array_select_sort(int array[], size_t len)
                    {
                        // TODO
                    }
                    
                    /*
                     * Tests
                     */
                    
                    static inline
                    double time_gdiff(struct timespec t0, struct timespec t1)
                    {
                        double s = t1.tv_sec - t0.tv_sec;
                        s += (t1.tv_nsec - t0.tv_nsec) * 1e-9;
                        return s;
                    }
                    
                    static inline
                    void sort_help(int array[], size_t len, int maxval)
                    {
                        struct timespec t0, t1;
                        printf("Array before sort:\n");
                        array_print(array, len, maxval);
                        printf("  ... sorting ...\n");
                        clock_gettime(CLOCK_MONOTONIC, &t0);
                        array_select_sort(array, len);
                        clock_gettime(CLOCK_MONOTONIC, &t1);
                        printf("Array after sort:\n");
                        array_print(array, len, maxval);
                        printf("  time for sorting: %gs\n", time_gdiff(t0, t1));
                        printf("  sort check: %s\n", check(array_is_sorted(array, len)));
                    }
                    
                    void test_sorting(int array[], size_t len)
                    {
                        printf("*** Sorted array ***\n");
                        array_sorted_fill(array, len, STEP);
                        sort_help(array, len, STEP * (len - 1));
                    
                        printf("\n*** Reverse sorted array ***\n");
                        array_reverse_sorted_fill(array, len, STEP);
                        sort_help(array, len, STEP * (len - 1));
                    
                        printf("\n*** Random array ***\n");
                        array_random_fill(array, len, MAXVAL);
                        sort_help(array, len, MAXVAL);
                    }
                    
                    /*
                     * main
                     */
                    int main(int argc, char *argv[])
                    {
                        srandom(time(NULL));
                    
                        size_t len;
                        if (argc < 2)
                            errx(1, "must provide array length");
                        len = strtoul(argv[1], NULL, 10);
                        int *array = calloc(len, sizeof (int));
                    
                        test_sorting(array, len);
                        printf("\n");
                    
                        free(array);
                        return 0;
                    }
                
            

Finally, you can compile and test your code with the following commands:

                
                    $ make array_sorting
                    gc
                
                
                    c -Wall -Wextra -std=c99 -O2 -MMD   array_sorting.c   -o array_sorting
                    $ ./array_sorting 10
                    # ...snip...
                
            

Simple DirectMedia Layer (SDL)

Checking Libraries

First, you have to check that you have all the libraries you need. The pkg-config command gives the compiler options. Execute the commands below and check that you have the same results (the ls command prints the installation paths of the library).

                
                    $ pkg-config --cflags sdl
                    -D_GNU_SOURCE=1 -D_REENTRANT -I/usr/include/SDL
                    $ ls /usr/include/SDL/SDL.h /usr/include/SDL/SDL_image.h 
                    /usr/include/SDL/SDL.h  /usr/include/SDL/SDL_image.h
                
            

Makefile

The following Makefile is provided:

                
                    # Simple SDL mini Makefile
                    
                    CC=gcc
                    
                    CPPFLAGS= `pkg-config --cflags sdl` -MMD
                    CFLAGS= -Wall -Wextra -Werror -std=c99 -O3
                    LDFLAGS=
                    LDLIBS= `pkg-config --libs sdl` -lSDL_image
                    
                    all: display grayscale
                    
                    display: display.o
                    grayscale: pixel_operations.o grayscale.o
                    
                    grayscale.o: pixel_operations.h
                    
                    clean:
                    	${RM} *.o
                    	${RM} *.d
                    	${RM} display
                    	${RM} grayscale
                    
                    # END
                
            

Displaying an Image

You will display an image by using the SDL.

To do so, you have to:

Some parts of this code is not really interesting. So, some commented functions are given.

Initializing the SDL:

                
                    void init_sdl()
                    {
                        // Init only the video part.
                        // If it fails, die with an error message.
                        if(SDL_Init(SDL_INIT_VIDEO) == -1)
                            errx(1,"Could not initialize SDL: %s.\n", SDL_GetError());
                    }
                
            

Loading an image from a file:

                
                    SDL_Surface* load_image(char *path)
                    {
                        SDL_Surface *img;

                        // Load an image using SDL_image with format detection.
                        // If it fails, die with an error message.
                        img = IMG_Load(path);
                        if (!img)
                            errx(3, "can't load %s: %s", path, IMG_GetError());

                        return img;
                    }
                
            

Displaying an image:

                
                    SDL_Surface* display_image(SDL_Surface *img)
                    {
                        SDL_Surface *screen;

                        // Set the window to the same size as the image
                        screen = SDL_SetVideoMode(img->w, img->h, 0, SDL_SWSURFACE|SDL_ANYFORMAT);
                        if (screen == NULL)
                        {
                            // error management
                            errx(1, "Couldn't set %dx%d video mode: %s\n",
                                    img->w, img->h, SDL_GetError());
                        }

                        // Blit onto the screen surface
                        if(SDL_BlitSurface(img, NULL, screen, NULL) < 0)
                            warnx("BlitSurface error: %s\n", SDL_GetError());

                        // Update the screen
                        SDL_UpdateRect(screen, 0, 0, img->w, img->h);

                        // return the screen for further uses
                        return screen;
                    }
                
            

Waiting for a key to be pressed.

                
                    void wait_for_keypressed()
                    {
                        SDL_Event event;

                        // Wait for a key to be down.
                        do
                        {
                            SDL_PollEvent(&event);
                        } while(event.type != SDL_KEYDOWN);

                        // Wait for a key to be up.
                        do
                        {
                            SDL_PollEvent(&event);
                        } while(event.type != SDL_KEYUP);
                    }
                
            

To free the allocated memory, just use the following SDL function.

                
                    void SDL_FreeSurface(SDL_Surface *surface);
                
            

Be careful, two surfaces will be created.

So they both must be freed.

Finally, complete the display.c file below (replace the TODO comments only). Two pointers are used for the surface variables, but do not worry, you do not have to know what a pointer is to do or to understand this practical. For now, consider that pointers are just simple variables (and technically, they are). We will see them in details later on.

display.c
                
                    #include <err.h>
                    #include "SDL/SDL.h"
                    #include "SDL/SDL_image.h"

                    // TODO: Insert all the above functions.

                    int main()
                    {
                        SDL_Surface* image_surface;
                        SDL_Surface* screen_surface;

                        // TODO: Initialize the SDL

                        image_surface = load_image("my_image.jpg");
                        // TODO: Display the image.

                        // TODO: Wait for a key to be pressed.

                        // TODO: Free the image surface.
                        // TODO: Free the screen surface.

                        return 0;
                    }
                
            

You can compile and run your code by typing the following commands. Do not forget to put an image in the same folder as your executable file.

                
                    $ make display
                    gc
                
                
                    c -Wall -Wextra -Werror -std=c99 -O3 `pk
                
                
                    g-config --cflags sdl` -MMD  -c -o display.o display.c
                    gc
                
                
                    c   display.o  `pk
                
                
                    g-config --libs sdl` -lSDL_image -o display
                    $ ./display
                
            

Converting into Grayscale

Now that you can display an image, you are going to convert it into grayscale.

First, copy the display.c file to the grayscale.c file.

                
                    $ cp display.c grayscale.c
                
            

From now on, you will modify the grayscale.c file only.

The two following files are given.

pixel_operations.h
                
                    #ifndef PIXEL_OPERATIONS_H_
                    #define PIXEL_OPERATIONS_H_
                    
                    #include <stdlib.h>
                    #include <SDL.h>
                    
                    Uint32 get_pixel(SDL_Surface *surface, unsigned x, unsigned y);
                    void put_pixel(SDL_Surface *surface, unsigned x, unsigned y, Uint32 pixel);
                    void update_surface(SDL_Surface* screen, SDL_Surface* image);
                    
                    #endif
                
            
pixel_operations.c
                
                    // Simple get/put pixel for SDL
                    // Inspired by code from SDL documentation
                    // (http://www.libsdl.org/release/SDL-1.2.15/docs/html/guidevideo.html)
                    
                    #include <err.h>
                    #include "pixel_operations.h"
                    
                    static inline
                    Uint8* pixel_ref(SDL_Surface *surf, unsigned x, unsigned y)
                    {
                        int bpp = surf->format->BytesPerPixel;
                        return (Uint8*)surf->pixels + y * surf->pitch + x * bpp;
                    }
                    
                    Uint32 get_pixel(SDL_Surface *surface, unsigned x, unsigned y)
                    {
                        Uint8 *p = pixel_ref(surface, x, y);
                    
                        switch (surface->format->BytesPerPixel)
                        {
                            case 1:
                                return *p;
                    
                            case 2:
                                return *(Uint16 *)p;
                    
                            case 3:
                                if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
                                    return p[0] << 16 | p[1] << 8 | p[2];
                                else
                                    return p[0] | p[1] << 8 | p[2] << 16;
                    
                            case 4:
                                return *(Uint32 *)p;
                        }
                    
                        return 0;
                    }
                    
                    void put_pixel(SDL_Surface *surface, unsigned x, unsigned y, Uint32 pixel)
                    {
                        Uint8 *p = pixel_ref(surface, x, y);
                    
                        switch(surface->format->BytesPerPixel)
                        {
                            case 1:
                                *p = pixel;
                                break;
                    
                            case 2:
                                *(Uint16 *)p = pixel;
                                break;
                    
                            case 3:
                                if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
                                {
                                    p[0] = (pixel >> 16) & 0xff;
                                    p[1] = (pixel >> 8) & 0xff;
                                    p[2] = pixel & 0xff;
                                }
                                else
                                {
                                    p[0] = pixel & 0xff;
                                    p[1] = (pixel >> 8) & 0xff;
                                    p[2] = (pixel >> 16) & 0xff;
                                }
                                break;
                    
                            case 4:
                                *(Uint32 *)p = pixel;
                                break;
                        }
                    }
                    
                    void update_surface(SDL_Surface* screen, SDL_Surface* image)
                    {
                        if (SDL_BlitSurface(image, NULL, screen, NULL) < 0)
                            warnx("BlitSurface error: %s\n", SDL_GetError());
                    
                        SDL_UpdateRect(screen, 0, 0, image->w, image->h);
                    }
                
            

You do not have to understand the contents of these files. You just have to know how to use their functions.

Here are some examples that can be helpful.

If the coordinates of a pixel are x and y, you can get its value by using the get_pixel() function.

                
                    Uint32 pixel = get_pixel(image_surface, x, y);
                
            

If the coordinates of a pixel are x and y, you can set its value by using the put_pixel() function.

                
                    put_pixel(image_surface, x, y, pixel);
                
            

To get the RGB values of a pixel in the r, g, b variables, you can use the following instructions:

                
                    Uint8 r, g, b;
                    SDL_GetRGB(pixel, image_surface->format, &r, &g, &b);
                
            

To get a pixel value from RGB values you can use the following instruction:

                
                    Uint32 pixel = SDL_MapRGB(image_surface->format, r, g, b);
                
            

To get the width of your image, you can use the the following instruction:

                
                    int width = image_surface->w;
                
            

To get the height of your image, you can use the following instruction:

                
                    int height = image_surface->h;
                
            

To redraw the surfaces:

                
                    update_surface(screen_image, surface_image);
                
            

So now, rewrite the main function in the grayscale.c file. Do not modify the display.c file. You also have to include the pixel_operations.h file.

Your main function should follow the following steps:

You can compile and run your code by typing the following commands. Do not forget to put an image in the same folder as your executable file.

                
                    $ make grayscale
                    gc
                
                
                    c -Wall -Wextra -Werror -std=c99 -O3 `pk
                
                
                    g-config --cflags sdl` -MMD  -c -o grayscale.o grayscale.c
                    gc
                
                
                    c -Wall -Wextra -Werror -std=c99 -O3 `pk
                
                
                    g-config --cflags sdl` -MMD  -c -o pixel_operations.o pixel_operations.c
                    gc
                
                
                    c   grayscale.o pixel_operations.o  `pk
                
                
                    g-config --libs sdl` -lSDL_image -o grayscale
                    $ ./grayscale