source: abuse/trunk/src/imlib/filter.cpp @ 579

Last change on this file since 579 was 579, checked in by Sam Hocevar, 11 years ago

imlib: refactor the Filter and ColorFilter? classes.

File size: 4.4 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This software was released into the Public Domain. As with most public
7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
9 */
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include "common.h"
16
17#include "image.h"
18#include "filter.h"
19
20Filter::Filter(int colors)
21{
22    CONDITION(colors >= 0 && colors <= 256, "bad colors value");
23    m_size = colors;
24    m_table = (uint8_t *)malloc(m_size);
25    memset(m_table, 0, m_size * sizeof(*m_table));
26}
27
28// Creates a conversion filter from one palette to another
29Filter::Filter(palette *from, palette *to)
30{
31    m_size = Max(from->pal_size(), to->pal_size());
32    m_table = (uint8_t *)malloc(m_size);
33
34    uint8_t *dst = m_table;
35    uint8_t *src = (uint8_t *)from->addr();
36    int dk = to->darkest(1);
37
38    for (int i = 0; i < m_size; i++)
39    {
40       int r = *src++;
41       int g = *src++;
42       int b = *src++;
43       int color = to->find_closest(r, g, b);
44
45       // Make sure non-blacks don't get remapped to the transparency
46       if ((r || g || b) && to->red(color) == 0
47            && to->green(color) == 0 && to->blue(color) == 0)
48           color = dk;
49
50       *dst++ = color;
51    }
52}
53
54Filter::~Filter()
55{
56    free(m_table);
57}
58
59void Filter::Set(int color_num, int change_to)
60{
61    CONDITION(color_num >= 0 && color_num < m_size, "Bad colors_num");
62    m_table[color_num] = change_to;
63}
64
65void Filter::Apply(image *im)
66{
67    im->Lock();
68    uint8_t *dst = im->scan_line(0);
69    int npixels = im->Size().x * im->Size().y;
70    while (npixels--)
71    {
72        CONDITION(*dst < m_size, "not enough filter colors");
73        *dst = m_table[*dst];
74        dst++;
75    }
76    im->Unlock();
77}
78
79/* This is only ever used in the editor, when showing the toolbar. It
80 * does not look like it's very useful. */
81void Filter::PutImage(image *screen, image *im, vec2i pos)
82{
83    int cx1, cy1, cx2, cy2, x1 = 0, y1 = 0,
84        x2 = im->Size().x, y2 = im->Size().y;
85    screen->GetClip(cx1, cy1, cx2, cy2);
86
87    // See if the image gets clipped off the screen
88    if(pos.x >= cx2 || pos.y >= cy2 ||
89       pos.x + (x2 - x1) <= cx1 || pos.y + (y2 - y1) <= cy1)
90        return;
91
92    x1 += Max(cx1 - pos.x, 0);
93    y1 += Max(cy1 - pos.y, 0);
94    pos.x = Max(pos.x, cx1);
95    pos.y = Max(pos.y, cy1);
96    x2 = Min(x2, cx2 - pos.x + x1);
97    y2 = Min(y2, cy2 - pos.y + y1);
98
99    if(x1 >= x2 || y1 >= y2)
100        return;
101
102    int xl = x2 - x1;
103    int yl = y2 - y1;
104
105    screen->AddDirty(pos.x, pos.y, pos.x + xl, pos.y + yl);
106
107    screen->Lock();
108    im->Lock();
109
110    for(int j = 0; j < yl; j++)
111    {
112        uint8_t *source = im->scan_line(y1 + j) + x1;
113        uint8_t *dest = screen->scan_line(pos.y + j) + pos.x;
114
115        for(int i = 0; i < xl; i++, source++, dest++)
116            if (*source)
117                *dest = m_table[*source];
118    }
119
120    im->Unlock();
121    screen->Unlock();
122}
123
124ColorFilter::ColorFilter(palette *pal, int color_bits)
125{
126    int max = pal->pal_size();
127    int mul = 1 << (8 - color_bits);
128    m_size = 1 << color_bits;
129    m_table = (uint8_t *)malloc(m_size * m_size * m_size);
130
131    /* For each colour in the RGB cube, find the nearest palette element. */
132    for (int r = 0; r < m_size; r++)
133    for (int g = 0; g < m_size; g++)
134    for (int b = 0; b < m_size; b++)
135    {
136        int best = 256 * 256 * 3;
137        int color = 0;
138        uint8_t *pp = (uint8_t *)pal->addr();
139
140        for (int i = 0; i < max; i++)
141        {
142            int rd = *pp++ - r * mul,
143                gd = *pp++ - g * mul,
144                bd = *pp++ - b * mul;
145
146            int dist = rd * rd + bd * bd + gd * gd;
147            if (dist < best)
148            {
149                best = dist;
150                color = i;
151            }
152        }
153        m_table[(r * m_size + g) * m_size + b] = color;
154    }
155}
156
157ColorFilter::ColorFilter(spec_entry *e, bFILE *fp)
158{
159    fp->seek(e->offset, 0);
160    m_size = fp->read_uint16();
161    m_table = (uint8_t *)malloc(m_size * m_size * m_size);
162    fp->read(m_table, m_size * m_size * m_size);
163}
164
165ColorFilter::~ColorFilter()
166{
167    free(m_table);
168}
169
170size_t ColorFilter::DiskUsage()
171{
172    return sizeof(uint16_t) + m_size * m_size * m_size;
173}
174
175int ColorFilter::Write(bFILE *fp)
176{
177    fp->write_uint16(m_size);
178    int bytes = m_size * m_size * m_size;
179    return fp->write(m_table, bytes) == bytes;
180}
181
Note: See TracBrowser for help on using the repository browser.