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"
32 #define RESIDENT_DIVISIONS 200
35 template <int disk_support
>
36 class image_ale_real
: public image
{
39 * Data structures without file support.
45 * Data structures for 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
;
55 mutable thread::rwlock_t rwlock
;
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
,
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
];
89 fprintf(stderr
, "Could not allocate memory for image data.\n");
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");
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
];
128 for (unsigned int i
= 0; i
< dimy
; i
++) {
129 unsigned int c
= fwrite(zero
, sizeof(spixel
), dimx
, support
);
131 ui::get()->error_hint("Image array support file error.",
132 "Submit a bug report.");
139 virtual ~image_ale_real() {
140 if (disk_support
== 0) {
143 for (int i
= 0; i
< RESIDENT_DIVISIONS
; i
++) {
145 delete[] _p_segments
[i
];
152 void resident_begin(unsigned int segment
) const {
154 if (_p_segments
[segment
])
160 if (_p_segments
[segment
])
163 if (resident_list
[resident_next
] >= 0) {
168 if (dirty_segments
[resident_list
[resident_next
]]) {
169 fseek(support
, rows_per_segment
* _dimx
* sizeof(spixel
)
170 * resident_list
[resident_next
],
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
)
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.
203 if (resident_next
>= resident_max
)
207 void resident_end(unsigned int segment
) const {
211 spixel
get_pixel(unsigned int y
, unsigned int x
) const {
215 if (disk_support
== 0) {
216 return _p
[y
* _dimx
+ x
];
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
);
231 void set_pixel(unsigned int y
, unsigned int x
, spixel p
) {
235 if (disk_support
== 0) {
236 _p
[y
* _dimx
+ x
] = p
;
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
) {
254 if (disk_support
== 0) {
255 _p
[y
* _dimx
+ x
] *= p
;
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
) {
273 if (disk_support
== 0) {
274 _p
[y
* _dimx
+ x
] += p
;
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 {
292 if (disk_support
== 0) {
293 return _p
[y
* _dimx
+ x
][k
];
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
);
309 void set_chan(unsigned int y
, unsigned int x
, unsigned int k
, ale_sreal c
) {
313 if (disk_support
== 0) {
314 _p
[y
* _dimx
+ x
][k
] = c
;
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
) {
332 if (disk_support
== 0) {
333 _p
[y
* _dimx
+ x
][k
] /= c
;
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
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
);
367 unsigned int min_i
= (-top
> 0)
371 unsigned int min_j
= (-left
> 0)
375 unsigned int max_i
= (height() < is
->height() - top
)
377 : is
->height() - top
;
379 unsigned int max_j
= (width() < is
->width() - left
)
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
);
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
,
408 const char *name
= "anonymous",
409 exposure
*exp
= NULL
) {
411 return image_ale_real
<0>::new_image_ale_real(dimy
, dimx
, depth
, name
, exp
);