aboutsummaryrefslogtreecommitdiff
path: root/src/graphics/image.c
blob: 0a6a88abcf4df5b2a90d994bbfe80c40c1c0a816 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include "../../include/mgl/graphics/image.h"
#include <assert.h>

#define STBI_NO_PSD
#define STBI_NO_TGA
#define STBI_NO_HDR
#define STBI_NO_PIC
#define STBI_NO_PNM
#define STB_IMAGE_IMPLEMENTATION
#include "../../external/stb_image.h"

static mgl_image_format stbi_format_to_mgl_image_format(int stbi_format) {
    switch(stbi_format) {
        case STBI_grey:
            return MGL_IMAGE_FORMAT_GRAY;
        case STBI_grey_alpha:
            return MGL_IMAGE_FORMAT_GRAY_ALPHA;
        case STBI_rgb:
            return MGL_IMAGE_FORMAT_RGB;
        case STBI_rgb_alpha:
            return MGL_IMAGE_FORMAT_RGBA;
    }
    assert(0);
    return MGL_IMAGE_FORMAT_RGBA;
}

static size_t mgl_image_format_num_channels(mgl_image_format image_format) {
    switch(image_format) {
        case MGL_IMAGE_FORMAT_ALPHA:        return 1;
        case MGL_IMAGE_FORMAT_GRAY:         return 1;
        case MGL_IMAGE_FORMAT_GRAY_ALPHA:   return 2;
        case MGL_IMAGE_FORMAT_RGB:          return 3;
        case MGL_IMAGE_FORMAT_RGBA:         return 4;
    }
    assert(0);
    return 4;
}

/* TODO: Ensure texture is power of 2 if the hardware doesn't support non power of two textures */
/* TODO: Verify if source format should always be 4 components (RGBA) because apparently if its another format then opengl will internally convert it to RGBA */
int mgl_image_load_from_file(mgl_image *self, const char *filepath) {
    self->data = NULL;
    self->width = 0;
    self->height = 0;
    
    int format;
    /* TODO: format is forced to rgba right now because rgb images cause the image to be skewed (bug) */
    self->data = stbi_load(filepath, &self->width, &self->height, &format, 4);
    if(!self->data) {
        fprintf(stderr, "Error: failed to load image %s, error: %s\n", filepath, stbi_failure_reason());
        mgl_image_unload(self);
        return -1;
    }
    format = 4;
    self->format = stbi_format_to_mgl_image_format(format);

    return 0;
}

/* TODO: Ensure texture is power of 2 if the hardware doesn't support non power of two textures */
/* TODO: Verify if source format should always be 4 components (RGBA) because apparently if its another format then opengl will internally convert it to RGBA */
int mgl_image_load_from_memory(mgl_image *self, const unsigned char *data, size_t size) {
    self->data = NULL;
    self->width = 0;
    self->height = 0;
    
    int format;
    /* TODO: format is forced to rgba right now because rgb images cause the image to be skewed (bug) */
    self->data = stbi_load_from_memory(data, size, &self->width, &self->height, &format, 4);
    if(!self->data) {
        fprintf(stderr, "Error: failed to load image from memory, error: %s\n", stbi_failure_reason());
        mgl_image_unload(self);
        return -1;
    }
    format = 4;
    self->format = stbi_format_to_mgl_image_format(format);

    return 0;
}

void mgl_image_unload(mgl_image *self) {
    if(self->data) {
        stbi_image_free(self->data);
        self->data = NULL;
    }
    self->width = 0;
    self->height = 0;
    self->format = 0;
}

size_t mgl_image_get_size(const mgl_image *self) {
    return (size_t)self->width * (size_t)self->height * mgl_image_format_num_channels(self->format);
}

int mgl_image_get_num_channels(const mgl_image *self) {
    return mgl_image_format_num_channels(self->format);
}