1/**
2 * \file
3 * \brief BMP Loader
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stddef.h>
16#include <stdint.h>
17#include <string.h>
18#include <assert.h>
19
20#include "bmp.h"
21
22#define MUST(x)         if(!(x)) return 1;
23
24struct bmp_header {
25    char        header[2];
26    uint32_t    size;
27    uint32_t    reserved;
28    uint32_t    bitmap_start;
29} __attribute__ ((packed));
30
31enum comp_alg {
32    COMP_BI_RGB         = 0,
33    COMP_BI_RLE8        = 1,
34    COMP_BI_RLE4        = 2,
35    COMP_BI_BITFIELDS   = 3,
36    COMP_BI_JPEG        = 4,
37    COMP_BI_PNG         = 5
38};
39
40struct dib_header {
41    uint32_t            size;
42    uint32_t            width, height;
43    uint16_t            planes;
44    uint16_t            bpp;
45    enum comp_alg       compression;
46    uint32_t            image_size;
47    uint32_t            hres, vres;
48    uint32_t            colors, important;
49} __attribute__ ((packed));
50
51int bmp_load(void *data, size_t size)
52{
53    struct bmp_header *bh = data;
54    struct dib_header *dh = data + sizeof(struct bmp_header);
55
56    MUST(size > sizeof(struct bmp_header) + sizeof(struct dib_header));
57    MUST(!strncmp(bh->header, "BM", 2));
58    MUST(dh->size == 40);
59    MUST(dh->planes == 1);
60    MUST(dh->compression == COMP_BI_RGB);
61
62    char *bitmap = data + bh->bitmap_start;
63
64    assert(24 == dh->bpp);
65    assert(dh->height <= yres);
66    assert(dh->width <= xres);
67
68    size_t linesize = dh->image_size / dh->height;
69    int mbpp = dh->bpp / 8;
70
71    // BMPs are stored upside-down
72    for(size_t y = 0; y < dh->height; y++) {
73        for(size_t x = 0; x < dh->width; x++) {
74            SCREEN(x, y)[0] = bitmap[(linesize * (dh->height - y - 1)) + x * mbpp + 0];
75            SCREEN(x, y)[1] = bitmap[(linesize * (dh->height - y - 1)) + x * mbpp + 1];
76            SCREEN(x, y)[2] = bitmap[(linesize * (dh->height - y - 1)) + x * mbpp + 2];
77        }
78    }
79
80    return 0;
81}
82