// Copyright 2002, 2004 David Hilvert , // /* This file is part of the Anti-Lamenessing Engine. The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The Anti-Lamenessing Engine is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the Anti-Lamenessing Engine; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * render.h: A superclass for all rendering classes. */ #ifndef __render_h__ #define __render_h__ #include "transformation.h" #include "image.h" #include "point.h" #define ACTIVE_RENDERER_COUNT 30 /* * Class render accepts messages synchronizing rendering steps through the * methods sync(n) and sync(), and returns information about the currently * rendered image via methods get_image() and get_defined(). This class is * abstract, and must be subclassed to be instantiated. */ class render { private: static unsigned int rx_count; static exclusion *rx_parameters; static int rx_show; static render *directory[ACTIVE_RENDERER_COUNT]; static int directory_length; static int extend; static ale_pos scale_factor; static ale_real wt; image **queue; unsigned int queue_size; int step_num; int entry_number; static int strpfix(const char *a, const char *b) { return strncmp(a, b, strlen(a)); } protected: /* * Constructor */ render() { if (directory_length >= ACTIVE_RENDERER_COUNT) { fprintf(stderr, "\n\n*** Too many renderers in d2::render::render() ***\n\n"); exit(1); } directory[directory_length] = this; entry_number = directory_length; directory_length++; step_num = -1; queue = NULL; queue_size = 0; } /* * Get extension state */ int is_extend() { return extend; } /* * Get the scale factor */ ale_pos get_scale_factor() { return scale_factor; } /* * Get the current step number */ int get_step() { return step_num; } /* * Perform the current rendering step. */ virtual void step() = 0; public: /* * Check for render-coordinate excluded regions. (Applies an offset to * spatial coordinates internally.) */ static int is_excluded_r(point offset, point p, int f) { for (unsigned int param = 0; param < rx_count; param++) if (rx_parameters[param].type == exclusion::RENDER && p[0] + offset[0] >= rx_parameters[param].x[0] && p[0] + offset[0] <= rx_parameters[param].x[1] && p[1] + offset[1] >= rx_parameters[param].x[2] && p[1] + offset[1] <= rx_parameters[param].x[3] && f >= rx_parameters[param].x[4] && f <= rx_parameters[param].x[5]) return 1; return 0; } static int is_excluded_r(point offset, int i, int j, int f) { for (unsigned int param = 0; param < rx_count; param++) if (rx_parameters[param].type == exclusion::RENDER && i + offset[0] >= rx_parameters[param].x[0] && i + offset[0] <= rx_parameters[param].x[1] && j + offset[1] >= rx_parameters[param].x[2] && j + offset[1] <= rx_parameters[param].x[3] && f >= rx_parameters[param].x[4] && f <= rx_parameters[param].x[5]) return 1; return 0; } int is_excluded_r(int i, int j, int f) { return is_excluded_r(get_image()->offset(), i, j, f); } /* * Check for frame-coordinate excluded regions. */ static int is_excluded_f(point p, int f) { for (unsigned int param = 0; param < rx_count; param++) if (rx_parameters[param].type == exclusion::FRAME && p[0] >= rx_parameters[param].x[0] && p[0] <= rx_parameters[param].x[1] && p[1] >= rx_parameters[param].x[2] && p[1] <= rx_parameters[param].x[3] && f >= rx_parameters[param].x[4] && f <= rx_parameters[param].x[5]) return 1; return 0; } static int is_excluded_f(int i, int j, int f) { for (unsigned int param = 0; param < rx_count; param++) if (rx_parameters[param].type == exclusion::FRAME && i >= rx_parameters[param].x[0] && i <= rx_parameters[param].x[1] && j >= rx_parameters[param].x[2] && j <= rx_parameters[param].x[3] && f >= rx_parameters[param].x[4] && f <= rx_parameters[param].x[5]) return 1; return 0; } static int render_count() { return directory_length; } static render *render_num(int n) { assert (n < directory_length); return directory[n]; } static void render_init(unsigned int _rx_count, exclusion *_rx_parameters, int _rx_show, int _extend, ale_pos _scale_factor) { rx_count = _rx_count; rx_show = _rx_show; extend = _extend; scale_factor = _scale_factor; rx_parameters = (exclusion *) malloc(rx_count * sizeof(exclusion)); for (unsigned int region = 0; region < rx_count; region++) { rx_parameters[region] = _rx_parameters[region]; /* * Scale spatial rendering coordinates */ if (rx_parameters[region].type == exclusion::RENDER) for (int p = 0; p < 4; p++) rx_parameters[region].x[p] *= scale_factor; } } static void set_wt(ale_real _wt) { wt = _wt; } static ale_real get_wt() { return wt; } static int is_rx_show() { return rx_show; } static unsigned int get_rx_count() { return rx_count; } static const exclusion *get_rx_parameters() { return rx_parameters; } /* * Current rendering result. */ virtual const image *get_image() const = 0; /* * Result of rendering at the given frame. */ const image *get_image(unsigned int n) { sync(n); if (n == (unsigned int) step_num) return get_image(); n = step_num - n - 1; assert (n < queue_size); return queue[n]; } /* * Extend the rendering queue. */ void extend_queue(unsigned int n) { /* * Increase the size of the queue, if necessary, to * accommodate the given lag. */ if (n > queue_size) { unsigned int new_size = n; queue = (image **) realloc(queue, new_size * sizeof(image *)); assert(queue); if (queue == NULL) { fprintf(stderr, "\n\n*** VISE: Unable to allocate memory ***\n\n\n"); exit(1); } memset(queue + queue_size, 0, (new_size - queue_size) * sizeof(image *)); queue_size = new_size; } } /* * Definition map. Unit-depth image whose pixels are nonzero where * the image is defined. */ virtual const image *get_defined() const = 0; /* * Sync. */ virtual void sync(int n) { assert (step_num >= -1); for (int i = step_num + 1; i <= n; i++) { if (queue_size > 0 && step_num >= 0) { /* * Shift the current queue so that the new head remains at the * zero index. There are more time-efficient ways to handle * queues, but the benefits are not clear in this case. */ delete queue[queue_size - 1]; for (int i = queue_size - 1; i > 0; i--) { queue[i] = queue[i - 1]; } queue[0] = get_image()->clone("Render queue clone"); } step_num++; step(); } } /* * Perform any final rendering steps. Return a non-zero value if * anything changed. */ virtual int sync() { return 0; } /* * Set point rendering bounds, if possible. */ virtual void init_point_renderer(unsigned int h, unsigned int w, unsigned int d) { assert(0); fprintf(stderr, "Error: init_point_renderer() not supported by this renderer\n"); exit(1); } /* * Point render. */ virtual void point_render(unsigned int i, unsigned int j, unsigned int f, transformation t) { assert(0); fprintf(stderr, "Error: point_render() not supported by this renderer\n"); exit(1); } /* * Finish point rendering. */ virtual void finish_point_rendering() { assert(0); fprintf(stderr, "Error: finish_point_rendering() not supported by this renderer\n"); exit(1); } virtual ~render() { directory[entry_number] = NULL; } int entry() { return entry_number; } virtual void free_memory() = 0; static void free_entry(int n) { if (directory[n] != NULL) { directory[n]->free_memory(); delete directory[n]; directory[n] = NULL; } } static void free_all_memory() { for (int i = 0; i < ACTIVE_RENDERER_COUNT; i++) free_entry(i); directory_length = 0; } static void reset() { free_all_memory(); } }; #endif