bugs: Consider distinguishing default/non-default alignments for wrapper-spec'd ...
[Ale.git] / d2 / image_ale_real.h
blob0e7dd7103b76f11dce246a7f315ca0fff05115fc
1 // Copyright 2002, 2003, 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * image_ale_real.h: Image represented by an array of ale_reals
25 #ifndef __image_ale_real_h__
26 #define __image_ale_real_h__
28 #include "exposure/exposure.h"
29 #include "point.h"
30 #include "image.h"
32 #define RESIDENT_DIVISIONS 200
35 template <int disk_support>
36 class image_ale_real : public image {
37 private:
39 * Data structures without file support.
42 spixel *_p;
45 * Data structures for file support.
48 FILE *support;
49 mutable spixel *_p_segments[RESIDENT_DIVISIONS];
50 mutable int dirty_segments[RESIDENT_DIVISIONS];
51 mutable int resident_list[RESIDENT_DIVISIONS];
52 mutable int resident_next;
53 int resident_max;
54 int rows_per_segment;
55 mutable thread::rwlock_t rwlock;
57 public:
60 * Wrapper encapsulating details of the separation between the
61 * resident-checking implementation and non-checking.
64 static image *new_image_ale_real(unsigned int dimy,
65 unsigned int dimx,
66 unsigned int depth,
67 const char *name = "anonymous",
68 exposure *exp = NULL) {
70 double resident = image::get_resident();
72 if (resident == 0 || resident * 1000000 >= dimy * dimx)
73 return new image_ale_real<0>(dimy, dimx, depth, name, exp);
75 return new image_ale_real<1>(dimy, dimx, depth, name, exp);
79 image_ale_real (unsigned int dimy, unsigned int dimx, unsigned int
80 depth, const char *name = "anonymous", exposure *exp = NULL)
81 : image(dimy, dimx, depth, name, exp) {
83 if (disk_support == 0) {
84 _p = new spixel[dimx * dimy];
86 assert (_p);
88 if (!_p) {
89 fprintf(stderr, "Could not allocate memory for image data.\n");
90 exit(1);
92 } else {
93 rows_per_segment = (int) ceil((double) dimy / (double) RESIDENT_DIVISIONS);
95 assert (rows_per_segment > 0);
97 for (int i = 0; i < RESIDENT_DIVISIONS; i++) {
98 _p_segments[i] = NULL;
99 dirty_segments[i] = 0;
100 resident_list[i] = -1;
103 resident_max = (unsigned int) floor((image::get_resident() * 1000000)
104 / (rows_per_segment * dimx));
106 assert (resident_max <= RESIDENT_DIVISIONS);
108 if (resident_max == 0) {
109 ui::get()->error_hint(
110 "No segments resident in image array.",
111 "Try recompiling with more RESIDENT_DIVISIONS");
114 resident_next = 0;
116 support = tmpfile();
118 if (!support) {
119 ui::get()->error_hint(
120 "Unable to create temporary file to support image array.",
121 "Set --resident 0, or Win32/64 users might run as admin.");
124 spixel *zero = new spixel[dimx];
126 assert(zero);
128 for (unsigned int i = 0; i < dimy; i++) {
129 unsigned int c = fwrite(zero, sizeof(spixel), dimx, support);
130 if (c < dimx)
131 ui::get()->error_hint("Image array support file error.",
132 "Submit a bug report.");
135 delete[] zero;
139 virtual ~image_ale_real() {
140 if (disk_support == 0) {
141 delete[] _p;
142 } else {
143 for (int i = 0; i < RESIDENT_DIVISIONS; i++) {
144 if (_p_segments[i])
145 delete[] _p_segments[i];
148 fclose(support);
152 void resident_begin(unsigned int segment) const {
153 rwlock.rdlock();
154 if (_p_segments[segment])
155 return;
156 rwlock.unlock();
158 rwlock.wrlock();
160 if (_p_segments[segment])
161 return;
163 if (resident_list[resident_next] >= 0) {
165 * Eject a segment
168 if (dirty_segments[resident_list[resident_next]]) {
169 fseek(support, rows_per_segment * _dimx * sizeof(spixel)
170 * resident_list[resident_next],
171 SEEK_SET);
172 assert(_p_segments[resident_list[resident_next]]);
173 size_t fwrite_result = fwrite(_p_segments[resident_list[resident_next]],
174 sizeof(spixel), rows_per_segment * _dimx, support);
176 assert(fwrite_result == rows_per_segment * _dimx);
178 dirty_segments[resident_list[resident_next]] = 0;
181 delete[] _p_segments[resident_list[resident_next]];
182 _p_segments[resident_list[resident_next]] = NULL;
185 resident_list[resident_next] = segment;
187 _p_segments[segment] = new spixel[_dimx * rows_per_segment];
189 assert (_p_segments[segment]);
191 fseek(support, rows_per_segment * _dimx * sizeof(spixel)
192 * segment,
193 SEEK_SET);
195 size_t fread_result = fread(_p_segments[segment], sizeof(spixel), rows_per_segment * _dimx, support);
197 assert(fread_result == rows_per_segment * _dimx);
200 * Update the next ejection candidate.
202 resident_next++;
203 if (resident_next >= resident_max)
204 resident_next = 0;
207 void resident_end(unsigned int segment) const {
208 rwlock.unlock();
211 spixel get_pixel(unsigned int y, unsigned int x) const {
212 assert (x < _dimx);
213 assert (y < _dimy);
215 if (disk_support == 0) {
216 return _p[y * _dimx + x];
217 } else {
218 int segment = y / rows_per_segment;
219 assert (segment < RESIDENT_DIVISIONS);
221 resident_begin(segment);
223 spixel result = _p_segments[segment][(y % rows_per_segment) * _dimx + x];
225 resident_end(segment);
227 return result;
231 void set_pixel(unsigned int y, unsigned int x, spixel p) {
232 assert (x < _dimx);
233 assert (y < _dimy);
235 if (disk_support == 0) {
236 _p[y * _dimx + x] = p;
237 } else {
238 int segment = y / rows_per_segment;
239 assert (segment < RESIDENT_DIVISIONS);
241 resident_begin(segment);
243 _p_segments[segment][(y % rows_per_segment) * _dimx + x] = p;
244 dirty_segments[segment] = 1;
246 resident_end(segment);
250 void mul_pixel(unsigned int y, unsigned int x, spixel p) {
251 assert (x < _dimx);
252 assert (y < _dimy);
254 if (disk_support == 0) {
255 _p[y * _dimx + x] *= p;
256 } else {
257 int segment = y / rows_per_segment;
258 assert (segment < RESIDENT_DIVISIONS);
260 resident_begin(segment);
262 _p_segments[segment][(y % rows_per_segment) * _dimx + x] *= p;
263 dirty_segments[segment] = 1;
265 resident_end(segment);
269 void add_pixel(unsigned int y, unsigned int x, pixel p) {
270 assert (x < _dimx);
271 assert (y < _dimy);
273 if (disk_support == 0) {
274 _p[y * _dimx + x] += p;
275 } else {
276 int segment = y / rows_per_segment;
277 assert (segment < RESIDENT_DIVISIONS);
279 resident_begin(segment);
281 _p_segments[segment][(y % rows_per_segment) * _dimx + x] += p;
282 dirty_segments[segment] = 1;
284 resident_end(segment);
288 ale_sreal get_chan(unsigned int y, unsigned int x, unsigned int k) const {
289 assert (x < _dimx);
290 assert (y < _dimy);
292 if (disk_support == 0) {
293 return _p[y * _dimx + x][k];
294 } else {
295 int segment = y / rows_per_segment;
296 assert (segment < RESIDENT_DIVISIONS);
298 resident_begin(segment);
300 ale_sreal result = _p_segments[segment]
301 [(y % rows_per_segment) * _dimx + x][k];
303 resident_end(segment);
305 return result;
309 void set_chan(unsigned int y, unsigned int x, unsigned int k, ale_sreal c) {
310 assert (x < _dimx);
311 assert (y < _dimy);
313 if (disk_support == 0) {
314 _p[y * _dimx + x][k] = c;
315 } else {
316 int segment = y / rows_per_segment;
317 assert (segment < RESIDENT_DIVISIONS);
319 resident_begin(segment);
321 _p_segments[segment][(y % rows_per_segment) * _dimx + x][k] = c;
322 dirty_segments[segment] = 1;
324 resident_end(segment);
328 void div_chan(unsigned int y, unsigned int x, unsigned int k, ale_sreal c) {
329 assert (x < _dimx);
330 assert (y < _dimy);
332 if (disk_support == 0) {
333 _p[y * _dimx + x][k] /= c;
334 } else {
335 int segment = y / rows_per_segment;
336 assert (segment < RESIDENT_DIVISIONS);
338 resident_begin(segment);
340 _p_segments[segment][(y % rows_per_segment) * _dimx + x][k] /= c;
341 dirty_segments[segment] = 1;
343 resident_end(segment);
348 * Make a new image suitable for receiving scaled values.
350 virtual image *scale_generator(int height, int width, int depth, const char *name) const {
351 return new_image_ale_real(height, width, depth, name, _exp);
355 * Extend the image area to the top, bottom, left, and right,
356 * initializing the new image areas with black pixels. Negative values
357 * shrink the image.
359 image *_extend(int top, int bottom, int left, int right) {
361 image *is = new_image_ale_real (
362 height() + top + bottom,
363 width() + left + right , depth(), name, _exp);
365 assert(is);
367 unsigned int min_i = (-top > 0)
368 ? -top
369 : 0;
371 unsigned int min_j = (-left > 0)
372 ? -left
373 : 0;
375 unsigned int max_i = (height() < is->height() - top)
376 ? height()
377 : is->height() - top;
379 unsigned int max_j = (width() < is->width() - left)
380 ? width()
381 : is->width() - left;
383 for (unsigned int i = min_i; i < max_i; i++)
384 for (unsigned int j = min_j; j < max_j; j++)
385 is->set_pixel(i + top, j + left, get_pixel(i, j));
387 is->set_offset(_offset[0] - top, _offset[1] - left);
389 return is;
392 private:
393 void trigger(pixel multiplier) {
394 for (unsigned int i = 0; i < height(); i++)
395 for (unsigned int j = 0; j < width(); j++) {
396 mul_pixel(i, j, multiplier);
402 * Wrapper encapsulating details of the separation between the
403 * resident-checking implementation and non-checking.
405 static inline image *new_image_ale_real(unsigned int dimy,
406 unsigned int dimx,
407 unsigned int depth,
408 const char *name = "anonymous",
409 exposure *exp = NULL) {
411 return image_ale_real<0>::new_image_ale_real(dimy, dimx, depth, name, exp);
415 #endif