2011-12-10 13:25:22 +00:00
|
|
|
#include "shared/types.h"
|
|
|
|
#include "shared/constants.h"
|
|
|
|
#include "shared/functions.h"
|
|
|
|
#include "shared/system.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "IL/il.h"
|
|
|
|
#include "IL/ilu.h"
|
|
|
|
|
|
|
|
int render_width;
|
|
|
|
int render_height;
|
|
|
|
int render_quality;
|
|
|
|
static int _pixel_count;
|
|
|
|
static Array* render_zone = NULL;
|
|
|
|
static RenderFragment* scanline_up;
|
|
|
|
static RenderFragment* scanline_down;
|
|
|
|
static int scanline_left;
|
|
|
|
static int scanline_right;
|
|
|
|
static Color background_color;
|
|
|
|
static volatile int _dirty_left;
|
|
|
|
static volatile int _dirty_right;
|
|
|
|
static volatile int _dirty_up;
|
|
|
|
static volatile int _dirty_down;
|
|
|
|
static volatile int _dirty_count;
|
|
|
|
static Mutex* _lock;
|
|
|
|
|
|
|
|
static volatile int _interrupt = 0;
|
|
|
|
static volatile int _progress_pixels;
|
|
|
|
static volatile double _progress = 0.0;
|
|
|
|
static volatile double _progress_step_start = 0.0;
|
|
|
|
static volatile double _progress_step_length = 1.0;
|
|
|
|
|
|
|
|
#define RENDER_INVERSE 1
|
|
|
|
#define RENDER_WIREFRAME 1
|
|
|
|
|
|
|
|
static void _previewResize(int width, int height) {}
|
|
|
|
static void _previewClear(Color col) {}
|
|
|
|
static void _previewDraw(int x, int y, Color col) {}
|
|
|
|
static void _previewUpdate(double progress) {}
|
|
|
|
|
|
|
|
static PreviewCallbackResize _cb_preview_resize = _previewResize;
|
|
|
|
static PreviewCallbackClear _cb_preview_clear = _previewClear;
|
|
|
|
static PreviewCallbackDraw _cb_preview_draw = _previewDraw;
|
|
|
|
static PreviewCallbackUpdate _cb_preview_update = _previewUpdate;
|
|
|
|
|
|
|
|
void renderSave(FILE* f)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderLoad(FILE* f)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderSetSize(int width, int height)
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
|
|
|
|
if (render_zone != NULL)
|
|
|
|
{
|
|
|
|
/* Delete previous render zone */
|
|
|
|
for (x = 0; x < render_width; x++)
|
|
|
|
{
|
|
|
|
for (y = 0; y < render_height; y++)
|
|
|
|
{
|
|
|
|
arrayDelete(render_zone + (y * render_width + x));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(render_zone);
|
|
|
|
free(scanline_up);
|
|
|
|
free(scanline_down);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_lock == NULL)
|
|
|
|
{
|
|
|
|
_lock = mutexCreate();
|
|
|
|
}
|
|
|
|
|
|
|
|
render_width = width;
|
|
|
|
render_height = height;
|
|
|
|
render_zone = malloc(sizeof(Array) * width * height);
|
|
|
|
|
|
|
|
scanline_left = 0;
|
|
|
|
scanline_right = render_width - 1;
|
|
|
|
scanline_up = malloc(sizeof(RenderFragment) * width);
|
|
|
|
scanline_down = malloc(sizeof(RenderFragment) * width);
|
|
|
|
|
|
|
|
_dirty_left = render_width;
|
|
|
|
_dirty_right = -1;
|
|
|
|
_dirty_down = render_height;
|
|
|
|
_dirty_up = -1;
|
|
|
|
_dirty_count = 0;
|
2011-12-18 21:59:33 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
_pixel_count = render_width * render_height;
|
|
|
|
|
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < width; x++)
|
|
|
|
{
|
|
|
|
arrayCreate(render_zone + (y * width + x), sizeof(RenderFragment));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_cb_preview_resize(render_width, render_height);
|
|
|
|
_cb_preview_clear(background_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderSetQuality(int quality)
|
|
|
|
{
|
|
|
|
if (quality < 1)
|
|
|
|
{
|
|
|
|
render_quality = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
render_quality = quality;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderClear()
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
|
|
|
|
for (x = 0; x < render_width; x++)
|
|
|
|
{
|
|
|
|
for (y = 0; y < render_height; y++)
|
|
|
|
{
|
|
|
|
arrayClear(render_zone + (y * render_width + x));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scanline_left = 0;
|
|
|
|
scanline_right = render_width - 1;
|
2011-12-18 21:59:33 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
_progress = 0.0;
|
|
|
|
_interrupt = 0;
|
|
|
|
|
|
|
|
_cb_preview_clear(background_color);
|
|
|
|
_cb_preview_update(_progress * _progress_step_length + _progress_step_start);
|
|
|
|
|
|
|
|
_dirty_left = render_width;
|
|
|
|
_dirty_right = -1;
|
|
|
|
_dirty_down = render_height;
|
|
|
|
_dirty_up = -1;
|
|
|
|
_dirty_count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderInterrupt()
|
|
|
|
{
|
|
|
|
_interrupt = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderSetBackgroundColor(Color* col)
|
|
|
|
{
|
|
|
|
background_color = *col;
|
|
|
|
}
|
|
|
|
|
|
|
|
double renderGetPrecision(Vector3 location)
|
|
|
|
{
|
|
|
|
Vector3 projected;
|
|
|
|
|
|
|
|
projected = cameraProject(location);
|
|
|
|
projected.x += 1.0;
|
|
|
|
//projected.y += 1.0;
|
|
|
|
|
|
|
|
return v3Norm(v3Sub(cameraUnproject(projected), location)); // / (double)render_quality;
|
|
|
|
}
|
|
|
|
|
|
|
|
int _sortRenderFragment(void const* a, void const* b)
|
|
|
|
{
|
|
|
|
double za, zb;
|
|
|
|
za = ((RenderFragment*)a)->z;
|
|
|
|
zb = ((RenderFragment*)b)->z;
|
|
|
|
if (za > zb)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else if (za < zb)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Color _getPixelColor(Array* pixel_data)
|
|
|
|
{
|
|
|
|
RenderFragment* fragment;
|
|
|
|
Color result = background_color;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (pixel_data->length > 0)
|
|
|
|
{
|
|
|
|
for (i = 0; i < pixel_data->length; i++)
|
|
|
|
{
|
|
|
|
fragment = ((RenderFragment*)pixel_data->data) + i;
|
|
|
|
colorMask(&result, &(fragment->vertex.color));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void _setDirtyPixel(Array* pixel_data, int x, int y)
|
|
|
|
{
|
|
|
|
pixel_data->dirty = 1;
|
|
|
|
if (x < _dirty_left)
|
|
|
|
{
|
|
|
|
_dirty_left = x;
|
|
|
|
}
|
|
|
|
if (x > _dirty_right)
|
|
|
|
{
|
|
|
|
_dirty_right = x;
|
|
|
|
}
|
|
|
|
if (y < _dirty_down)
|
|
|
|
{
|
|
|
|
_dirty_down = y;
|
|
|
|
}
|
|
|
|
if (y > _dirty_up)
|
|
|
|
{
|
|
|
|
_dirty_up = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
_dirty_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _processDirtyPixels()
|
|
|
|
{
|
|
|
|
Color col;
|
|
|
|
Array* pixel_data;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
for (y = _dirty_down; y <= _dirty_up; y++)
|
|
|
|
{
|
|
|
|
for (x = _dirty_left; x <= _dirty_right; x++)
|
|
|
|
{
|
|
|
|
pixel_data = render_zone + y * render_width + x;
|
|
|
|
if (pixel_data->dirty)
|
|
|
|
{
|
|
|
|
col = _getPixelColor(pixel_data);
|
|
|
|
_cb_preview_draw(x, y, col);
|
|
|
|
pixel_data->dirty = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_cb_preview_update(_progress * _progress_step_length + _progress_step_start);
|
|
|
|
|
|
|
|
_dirty_left = render_width;
|
|
|
|
_dirty_right = -1;
|
|
|
|
_dirty_down = render_height;
|
|
|
|
_dirty_up = -1;
|
|
|
|
_dirty_count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderAddFragment(RenderFragment* fragment)
|
|
|
|
{
|
|
|
|
Array* pixel_data;
|
|
|
|
int x = fragment->x;
|
|
|
|
int y = fragment->y;
|
|
|
|
double z = fragment->z;
|
|
|
|
|
|
|
|
int i, dirty;
|
|
|
|
int fragments_count;
|
|
|
|
RenderFragment* fragments;
|
|
|
|
|
|
|
|
dirty = 0;
|
|
|
|
if (x >= 0 && x < render_width && y >= 0 && y < render_height && z > 1.0)
|
|
|
|
{
|
|
|
|
pixel_data = render_zone + (y * render_width + x);
|
|
|
|
fragments = (RenderFragment*)pixel_data->data;
|
|
|
|
fragments_count = pixel_data->length;
|
|
|
|
|
|
|
|
if (fragments_count == 0)
|
|
|
|
{
|
|
|
|
arrayAppend(pixel_data, fragment);
|
|
|
|
dirty = 1;
|
|
|
|
}
|
|
|
|
else if (fragments[0].z > z)
|
|
|
|
{
|
|
|
|
if (fragments[0].vertex.color.a < 1.0)
|
|
|
|
{
|
|
|
|
arrayInsert(pixel_data, fragment, 0);
|
|
|
|
dirty = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 1; i <= fragments_count; i++)
|
|
|
|
{
|
|
|
|
if ((i == fragments_count) || (fragments[i].z > z))
|
|
|
|
{
|
|
|
|
if (fragment->vertex.color.a > 0.999999)
|
|
|
|
{
|
|
|
|
if (i > 1)
|
|
|
|
{
|
|
|
|
arrayLStrip(pixel_data, i - 1);
|
|
|
|
}
|
|
|
|
arrayReplace(pixel_data, fragment, 0);
|
|
|
|
}
|
|
|
|
else if (i == fragments_count)
|
|
|
|
{
|
|
|
|
arrayAppend(pixel_data, fragment);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arrayInsert(pixel_data, fragment, i);
|
|
|
|
}
|
|
|
|
dirty = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirty)
|
|
|
|
{
|
|
|
|
_setDirtyPixel(pixel_data, x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderPushFragment(int x, int y, double z, Vertex* vertex)
|
|
|
|
{
|
|
|
|
RenderFragment fragment;
|
|
|
|
|
|
|
|
fragment.x = x;
|
|
|
|
fragment.y = y;
|
|
|
|
fragment.z = z;
|
|
|
|
fragment.vertex = *vertex;
|
|
|
|
|
|
|
|
renderAddFragment(&fragment);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __vertexGetDiff(Vertex* v1, Vertex* v2, Vertex* result)
|
|
|
|
{
|
|
|
|
result->location.x = v2->location.x - v1->location.x;
|
|
|
|
result->location.y = v2->location.y - v1->location.y;
|
|
|
|
result->location.z = v2->location.z - v1->location.z;
|
|
|
|
result->normal.x = v2->normal.x - v1->normal.x;
|
|
|
|
result->normal.y = v2->normal.y - v1->normal.y;
|
|
|
|
result->normal.z = v2->normal.z - v1->normal.z;
|
|
|
|
result->color.r = v2->color.r - v1->color.r;
|
|
|
|
result->color.g = v2->color.g - v1->color.g;
|
|
|
|
result->color.b = v2->color.b - v1->color.b;
|
|
|
|
result->color.a = v2->color.a - v1->color.a;
|
|
|
|
result->callback = v1->callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __vertexInterpolate(Vertex* v1, Vertex* diff, double value, Vertex* result)
|
|
|
|
{
|
|
|
|
result->location.x = v1->location.x + diff->location.x * value;
|
|
|
|
result->location.y = v1->location.y + diff->location.y * value;
|
|
|
|
result->location.z = v1->location.z + diff->location.z * value;
|
|
|
|
result->normal.x = v1->normal.x + diff->normal.x * value;
|
|
|
|
result->normal.y = v1->normal.y + diff->normal.y * value;
|
|
|
|
result->normal.z = v1->normal.z + diff->normal.z * value;
|
|
|
|
result->color.r = v1->color.r + diff->color.r * value;
|
|
|
|
result->color.g = v1->color.g + diff->color.g * value;
|
|
|
|
result->color.b = v1->color.b + diff->color.b * value;
|
|
|
|
result->color.a = v1->color.a + diff->color.a * value;
|
|
|
|
result->callback = v1->callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __pushScanLinePoint(RenderFragment point)
|
|
|
|
{
|
|
|
|
if (point.x < 0 || point.x >= render_width)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (point.x > scanline_right)
|
|
|
|
{
|
|
|
|
scanline_right = point.x;
|
|
|
|
scanline_up[scanline_right] = point;
|
|
|
|
scanline_down[scanline_right] = point;
|
|
|
|
if (point.x < scanline_left)
|
|
|
|
{
|
|
|
|
scanline_left = point.x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (point.x < scanline_left)
|
|
|
|
{
|
|
|
|
scanline_left = point.x;
|
|
|
|
scanline_up[scanline_left] = point;
|
|
|
|
scanline_down[scanline_left] = point;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (point.y > scanline_up[point.x].y)
|
|
|
|
{
|
|
|
|
scanline_up[point.x] = point;
|
|
|
|
}
|
|
|
|
if (point.y < scanline_down[point.x].y)
|
|
|
|
{
|
|
|
|
scanline_down[point.x] = point;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __pushScanLineEdge(Vector3 v1, Vector3 v2, Vertex* vertex1, Vertex* vertex2)
|
|
|
|
{
|
|
|
|
double dx, dy, dz, fx;
|
|
|
|
Vertex diff;
|
|
|
|
int startx = lround(v1.x);
|
|
|
|
int endx = lround(v2.x);
|
|
|
|
int curx;
|
|
|
|
RenderFragment fragment;
|
|
|
|
|
|
|
|
if (endx < startx)
|
|
|
|
{
|
|
|
|
__pushScanLineEdge(v2, v1, vertex2, vertex1);
|
|
|
|
}
|
|
|
|
else if (endx < 0 || startx >= render_width)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (startx == endx)
|
|
|
|
{
|
|
|
|
fragment.x = startx;
|
|
|
|
fragment.y = lround(v1.y);
|
|
|
|
fragment.z = v1.z;
|
|
|
|
fragment.vertex = *vertex1;
|
|
|
|
|
|
|
|
__pushScanLinePoint(fragment);
|
|
|
|
|
|
|
|
fragment.x = endx;
|
|
|
|
fragment.y = lround(v2.y);
|
|
|
|
fragment.z = v2.z;
|
|
|
|
fragment.vertex = *vertex2;
|
|
|
|
|
|
|
|
__pushScanLinePoint(fragment);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (startx < 0)
|
|
|
|
{
|
|
|
|
startx = 0;
|
|
|
|
}
|
|
|
|
if (endx >= render_width)
|
|
|
|
{
|
|
|
|
endx = render_width - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dx = v2.x - v1.x;
|
|
|
|
dy = v2.y - v1.y;
|
|
|
|
dz = v2.z - v1.z;
|
|
|
|
__vertexGetDiff(vertex1, vertex2, &diff);
|
|
|
|
for (curx = startx; curx <= endx; curx++)
|
|
|
|
{
|
|
|
|
fx = (double)curx + 0.5;
|
|
|
|
if (fx < v1.x)
|
|
|
|
{
|
|
|
|
fx = v1.x;
|
|
|
|
}
|
|
|
|
else if (fx > v2.x)
|
|
|
|
{
|
|
|
|
fx = v2.x;
|
|
|
|
}
|
|
|
|
fx = fx - v1.x;
|
|
|
|
fragment.x = curx;
|
|
|
|
fragment.y = lround(v1.y + dy * fx / dx);
|
|
|
|
fragment.z = v1.z + dz * fx / dx;
|
|
|
|
__vertexInterpolate(vertex1, &diff, fx / dx, &(fragment.vertex));
|
|
|
|
|
|
|
|
__pushScanLinePoint(fragment);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __clearScanLines()
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
for (x = scanline_left; x <= scanline_right; x++)
|
|
|
|
{
|
|
|
|
scanline_up[x].y = -1;
|
|
|
|
scanline_down[x].y = render_height;
|
|
|
|
}
|
|
|
|
scanline_left = render_width;
|
|
|
|
scanline_right = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __renderScanLines()
|
|
|
|
{
|
|
|
|
int x, starty, endy, cury;
|
|
|
|
Vertex diff;
|
|
|
|
double dy, dz, fy;
|
|
|
|
RenderFragment up, down, current;
|
|
|
|
|
|
|
|
if (scanline_right > 0)
|
|
|
|
{
|
|
|
|
for (x = scanline_left; x <= scanline_right; x++)
|
|
|
|
{
|
|
|
|
up = scanline_up[x];
|
|
|
|
down = scanline_down[x];
|
|
|
|
|
|
|
|
starty = down.y;
|
|
|
|
endy = up.y;
|
|
|
|
|
|
|
|
if (endy < 0 || starty >= render_height)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (starty < 0)
|
|
|
|
{
|
|
|
|
starty = 0;
|
|
|
|
}
|
|
|
|
if (endy >= render_height)
|
|
|
|
{
|
|
|
|
endy = render_height - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dy = (double)(up.y - down.y);
|
|
|
|
dz = up.z - down.z;
|
|
|
|
__vertexGetDiff(&down.vertex, &up.vertex, &diff);
|
|
|
|
|
|
|
|
current.x = x;
|
|
|
|
for (cury = starty; cury <= endy; cury++)
|
|
|
|
{
|
|
|
|
fy = (double)cury - down.y;
|
|
|
|
|
|
|
|
current.y = cury;
|
|
|
|
current.z = down.z + dz * fy / dy;
|
|
|
|
__vertexInterpolate(&down.vertex, &diff, fy / dy, ¤t.vertex);
|
|
|
|
|
|
|
|
#ifdef RENDER_WIREFRAME
|
|
|
|
if (cury == starty || cury == endy)
|
|
|
|
{
|
|
|
|
current.vertex.color = COLOR_RED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
renderAddFragment(¤t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderPushTriangle(Vertex* v1, Vertex* v2, Vertex* v3)
|
|
|
|
{
|
|
|
|
Vector3 p1, p2, p3;
|
|
|
|
double limit_width = (double)(render_width - 1);
|
|
|
|
double limit_height = (double)(render_height - 1);
|
|
|
|
|
|
|
|
p1 = cameraProject(v1->location);
|
|
|
|
p2 = cameraProject(v2->location);
|
|
|
|
p3 = cameraProject(v3->location);
|
|
|
|
|
|
|
|
/* Filter if outside screen */
|
|
|
|
if (p1.z < 1.0 || p2.z < 1.0 || p3.z < 1.0 || (p1.x < 0.0 && p2.x < 0.0 && p3.x < 0.0) || (p1.y < 0.0 && p2.y < 0.0 && p3.y < 0.0) || (p1.x > limit_width && p2.x > limit_width && p3.x > limit_width) || (p1.y > limit_height && p2.y > limit_height && p3.y > limit_height))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
__clearScanLines();
|
|
|
|
__pushScanLineEdge(p1, p2, v1, v2);
|
|
|
|
__pushScanLineEdge(p2, p3, v2, v3);
|
|
|
|
__pushScanLineEdge(p3, p1, v3, v1);
|
|
|
|
mutexAcquire(_lock);
|
|
|
|
__renderScanLines();
|
|
|
|
mutexRelease(_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderPushQuad(Vertex* v1, Vertex* v2, Vertex* v3, Vertex* v4)
|
|
|
|
{
|
|
|
|
renderPushTriangle(v2, v3, v1);
|
|
|
|
renderPushTriangle(v4, v1, v3);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
int startx;
|
|
|
|
int endx;
|
|
|
|
int starty;
|
|
|
|
int endy;
|
|
|
|
int finished;
|
|
|
|
int interrupt;
|
|
|
|
Thread* thread;
|
|
|
|
} RenderChunk;
|
|
|
|
|
|
|
|
void* _renderPostProcessChunk(void* data)
|
|
|
|
{
|
|
|
|
int x, y, i;
|
|
|
|
int dirty;
|
|
|
|
Array* pixel_data;
|
|
|
|
RenderFragment* fragments;
|
|
|
|
RenderChunk* chunk = (RenderChunk*)data;
|
|
|
|
|
|
|
|
#ifdef RENDER_INVERSE
|
|
|
|
for (y = render_height - 1 - chunk->starty; y >= render_height - 1 - chunk->endy; y--)
|
|
|
|
#else
|
|
|
|
for (y = chunk->starty; y <= chunk->endy; y++)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
for (x = chunk->startx; x <= chunk->endx; x++)
|
|
|
|
{
|
|
|
|
pixel_data = render_zone + (y * render_width + x);
|
|
|
|
fragments = (RenderFragment*)pixel_data->data;
|
|
|
|
dirty = 0;
|
|
|
|
for (i = 0; i < pixel_data->length; i++)
|
|
|
|
{
|
|
|
|
if (fragments[i].vertex.callback)
|
|
|
|
{
|
|
|
|
if (fragments[i].vertex.callback(fragments + i))
|
|
|
|
{
|
|
|
|
/* TODO Store over-exposure */
|
|
|
|
colorNormalize(&fragments[i].vertex.color);
|
|
|
|
dirty = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dirty)
|
|
|
|
{
|
|
|
|
mutexAcquire(_lock);
|
|
|
|
_setDirtyPixel(pixel_data, x, y);
|
|
|
|
mutexRelease(_lock);
|
|
|
|
}
|
|
|
|
_progress_pixels++;
|
|
|
|
}
|
|
|
|
if (chunk->interrupt)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
chunk->finished = 1;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_CHUNKS 8
|
|
|
|
void renderPostProcess(int nbchunks)
|
|
|
|
{
|
|
|
|
volatile RenderChunk chunks[MAX_CHUNKS];
|
|
|
|
int i;
|
|
|
|
int x, y, dx, dy, nx, ny;
|
|
|
|
int loops, running;
|
|
|
|
|
|
|
|
if (nbchunks > MAX_CHUNKS)
|
|
|
|
{
|
|
|
|
nbchunks = MAX_CHUNKS;
|
|
|
|
}
|
|
|
|
if (nbchunks < 1)
|
|
|
|
{
|
|
|
|
nbchunks = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nx = 10;
|
|
|
|
ny = 10;
|
|
|
|
dx = render_width / nx;
|
|
|
|
dy = render_height / ny;
|
|
|
|
x = 0;
|
|
|
|
y = 0;
|
|
|
|
_progress_pixels = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < nbchunks; i++)
|
|
|
|
{
|
|
|
|
chunks[i].thread = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
running = 0;
|
|
|
|
loops = 0;
|
|
|
|
while ((y < ny && !_interrupt) || running > 0)
|
|
|
|
{
|
|
|
|
timeSleepMs(100);
|
|
|
|
|
|
|
|
for (i = 0; i < nbchunks; i++)
|
|
|
|
{
|
|
|
|
if (chunks[i].thread)
|
|
|
|
{
|
|
|
|
if (chunks[i].finished)
|
|
|
|
{
|
|
|
|
threadJoin(chunks[i].thread);
|
|
|
|
chunks[i].thread = NULL;
|
|
|
|
running--;
|
|
|
|
}
|
|
|
|
else if (_interrupt)
|
|
|
|
{
|
|
|
|
chunks[i].interrupt = 1;
|
|
|
|
}
|
|
|
|
}
|
2011-12-18 21:59:33 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
if (y < ny && !chunks[i].thread && !_interrupt)
|
|
|
|
{
|
|
|
|
chunks[i].finished = 0;
|
|
|
|
chunks[i].interrupt = 0;
|
|
|
|
chunks[i].startx = x * dx;
|
|
|
|
if (x == nx)
|
|
|
|
{
|
|
|
|
chunks[i].endx = render_width - 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
chunks[i].endx = (x + 1) * dx - 1;
|
|
|
|
}
|
|
|
|
chunks[i].starty = y * dy;
|
|
|
|
if (y == ny)
|
|
|
|
{
|
|
|
|
chunks[i].endy = render_height - 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
chunks[i].endy = (y + 1) * dy - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
chunks[i].thread = threadCreate(_renderPostProcessChunk, (void*)(chunks + i));
|
|
|
|
running++;
|
|
|
|
|
|
|
|
if (++x >= nx)
|
|
|
|
{
|
|
|
|
y++;
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (++loops >= 10)
|
|
|
|
{
|
|
|
|
mutexAcquire(_lock);
|
|
|
|
_progress = (double)_progress_pixels / (double)_pixel_count;
|
|
|
|
_processDirtyPixels();
|
|
|
|
mutexRelease(_lock);
|
|
|
|
|
|
|
|
loops = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_progress = 1.0;
|
|
|
|
_processDirtyPixels();
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderUpdate()
|
|
|
|
{
|
|
|
|
mutexAcquire(_lock);
|
|
|
|
_processDirtyPixels();
|
|
|
|
mutexRelease(_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderSaveToFile(const char* path)
|
|
|
|
{
|
|
|
|
ILuint image_id;
|
|
|
|
ilGenImages(1, &image_id);
|
|
|
|
ilBindImage(image_id);
|
|
|
|
Color result;
|
|
|
|
ILuint x, y;
|
|
|
|
ILuint rgba;
|
|
|
|
ILuint data[render_height * render_width];
|
|
|
|
ILenum error;
|
|
|
|
Array* pixel_data;
|
|
|
|
|
|
|
|
for (y = 0; y < render_height; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < render_width; x++)
|
|
|
|
{
|
|
|
|
pixel_data = render_zone + (y * render_width + x);
|
|
|
|
result = _getPixelColor(pixel_data);
|
|
|
|
rgba = colorTo32BitRGBA(&result);
|
|
|
|
data[y * render_width + x] = rgba;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ilTexImage((ILuint)render_width, (ILuint)render_height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, data);
|
|
|
|
ilSaveImage(path);
|
|
|
|
|
|
|
|
ilDeleteImages(1, &image_id);
|
|
|
|
|
|
|
|
while ((error=ilGetError()) != IL_NO_ERROR)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "IL ERROR : %s\n", iluErrorString(error));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderSetPreviewCallbacks(PreviewCallbackResize resize, PreviewCallbackClear clear, PreviewCallbackDraw draw, PreviewCallbackUpdate update)
|
|
|
|
{
|
|
|
|
_cb_preview_resize = resize ? resize : _previewResize;
|
|
|
|
_cb_preview_clear = clear ? clear : _previewClear;
|
|
|
|
_cb_preview_draw = draw ? draw : _previewDraw;
|
|
|
|
_cb_preview_update = update ? update : _previewUpdate;
|
|
|
|
_cb_preview_resize(render_width, render_height);
|
|
|
|
/* TODO Send all pixels ? */
|
|
|
|
}
|
|
|
|
|
|
|
|
int renderSetNextProgressStep(double start, double end)
|
|
|
|
{
|
|
|
|
if (_interrupt)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_progress = 0.0;
|
|
|
|
_progress_step_start = start;
|
|
|
|
_progress_step_length = end - start;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int renderTellProgress(double progress)
|
|
|
|
{
|
|
|
|
if (_interrupt)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_progress = progress;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|