quakeforge/tools/Forge/Bundles/MapEdit/render.m
Bill Currie d23300d58b Pass .m files through indent.
The result isn't perfect, but it cleans up the whitespace and makes the
code more consistent with the rest of the project.
2010-11-28 15:31:31 +09:00

718 lines
13 KiB
Objective-C

#include "render.h"
extern vec3_t xy_viewnormal;
//define NOLIGHT
vec3_t r_origin, r_matrix[3];
int t_width, t_height;
unsigned *t_data;
int t_widthmask, t_heightmask, t_widthshift;
float t_widthadd, t_heightadd;
int r_width, r_height;
float *r_zbuffer;
unsigned *r_picbuffer;
vec5_t rightside, leftside, rightstep, leftstep;
face_t *r_face;
BOOL r_drawflat;
pixel32_t r_flatcolor;
int sy[20];
/*
====================
REN_ClearBuffers
====================
*/
void
REN_ClearBuffers (void)
{
int size;
size = r_width * r_height * 4;
memset (r_zbuffer, 0, size);
memset (r_picbuffer, 0, size);
}
/*
====================
REN_SetTexture
====================
*/
void
REN_SetTexture (face_t * face)
{
int i;
int t_heightshift;
qtexture_t *q;
if (!face->qtexture)
face->qtexture = TEX_ForName (face->texture.texture); // try to load
q = face->qtexture;
t_width = q->width;
t_height = q->height;
t_data = q->data;
r_flatcolor = q->flatcolor;
r_flatcolor.chan[0] *= r_face->light;
r_flatcolor.chan[1] *= r_face->light;
r_flatcolor.chan[2] *= r_face->light;
t_widthadd = t_width * 1024;
t_heightadd = t_height * 1024;
t_widthmask = t_width - 1;
t_heightmask = t_height - 1;
t_widthshift = 0;
i = t_width;
while (i >= 2) {
t_widthshift++;
i >>= 1;
}
t_heightshift = 0;
i = t_width;
while (i >= 2) {
t_heightshift++;
i >>= 1;
}
if ((1 << t_widthshift) != t_width || (1 << t_heightshift) != t_height)
t_widthshift = t_heightshift = 0; // non power of two
}
/*
==================
REN_DrawSpan
==================
*/
void
REN_DrawSpan (int y)
{
int x, count;
int ofs;
int tx, ty;
int x1, x2;
float ufrac, vfrac, zfrac, lightfrac, ustep, vstep, zstep;
pixel32_t *in, *out;
float scale;
if (y < 0 || y >= r_height)
return;
x1 = (leftside[0]);
x2 = (rightside[0]);
count = x2 - x1;
if (count < 0)
return;
zfrac = leftside[2];
ufrac = leftside[3];
vfrac = leftside[4];
lightfrac = r_face->light;
if (!count)
scale = 1;
else
scale = 1.0 / count;
zstep = (rightside[2] - zfrac) * scale;
ustep = (rightside[3] - ufrac) * scale;
vstep = (rightside[4] - vfrac) * scale;
if (x1 < 0) {
ufrac -= x1 * ustep;
vfrac -= x1 * vstep;
zfrac -= x1 * zstep;
x1 = 0;
}
if (x2 > r_width)
x2 = r_width;
ofs = y * r_width + x1;
// this should be specialized for 1.0 / 0.5 / 0.75 light levels
for (x = x1; x < x2; x++) {
if (r_zbuffer[ofs] <= zfrac) {
scale = 1 / zfrac;
r_zbuffer[ofs] = zfrac;
if (t_widthshift) {
tx = (int) ((ufrac * scale)) & t_widthmask;
ty = (int) ((vfrac * scale)) & t_heightmask;
in = (pixel32_t *) & t_data[(ty << t_widthshift) + tx];
} else {
tx = (int) ((ufrac * scale) + t_widthadd) % t_width;
ty = (int) ((vfrac * scale) + t_heightadd) % t_height;
in = (pixel32_t *) & t_data[ty * t_width + tx];
}
out = (pixel32_t *) & r_picbuffer[ofs];
#ifdef NOLIGHT
*out = *in;
#else
out->chan[0] = in->chan[0] * lightfrac;
out->chan[1] = in->chan[1] * lightfrac;
out->chan[2] = in->chan[2] * lightfrac;
out->chan[3] = 0xff;
#endif
}
ufrac += ustep;
vfrac += vstep;
zfrac += zstep;
ofs++;
}
}
/*
==================
REN_DrawFlatSpan
==================
*/
void
REN_DrawFlatSpan (int y)
{
int x, count;
int ofs;
int x1, x2;
float zfrac, zstep;
int *out;
if (y < 0 || y >= r_height)
return;
x1 = (leftside[0]);
x2 = (rightside[0]);
count = x2 - x1;
if (count < 0)
return;
zfrac = leftside[2];
zstep = (rightside[2] - zfrac) / count;
if (x1 < 0) {
zfrac -= x1 * zstep;
x1 = 0;
}
if (x2 > r_width)
x2 = r_width;
ofs = y * r_width + x1;
// this should be specialized for 1.0 / 0.5 / 0.75 light levels
for (x = x1; x < x2; x++) {
if (r_zbuffer[ofs] <= zfrac) {
r_zbuffer[ofs] = zfrac;
out = (int *) &r_picbuffer[ofs];
*out = r_flatcolor.p;
}
zfrac += zstep;
ofs++;
}
}
/*
=====================
REN_RasterizeFace
=====================
*/
void
REN_RasterizeFace (winding_t * w)
{
int y;
int i;
int top, bot;
int leftv, rightv;
int count;
int numvertex;
//
// find top vertex
//
numvertex = w->numpoints;
top = 0x7fffffff;
bot = 0x80000000;
leftv = 0;
for (i = 0; i < numvertex; i++) {
w->points[i][3] *= w->points[i][2];
w->points[i][4] *= w->points[i][2];
sy[i] = (int) w->points[i][1];
if (sy[i] < top) {
top = sy[i];
leftv = i;
}
if (sy[i] > bot)
bot = sy[i];
}
rightv = leftv;
if (top < 0 || bot > r_height || top > bot)
return; // shouldn't have to have this...
//
// render a trapezoid
//
y = top;
while (y < bot) {
if (y >= sy[leftv]) {
do {
for (i = 0; i < 5; i++)
leftside[i] = w->points[leftv][i];
leftv--;
if (leftv == -1)
leftv = numvertex - 1;
} while (sy[leftv] <= y);
count = sy[leftv] - y;
for (i = 0; i < 5; i++)
leftstep[i] = (w->points[leftv][i] - leftside[i]) / count;
}
if (y >= sy[rightv]) {
do {
for (i = 0; i < 5; i++)
rightside[i] = w->points[rightv][i];
rightv++;
if (rightv == numvertex)
rightv = 0;
} while (sy[rightv] <= y);
count = sy[rightv] - y;
for (i = 0; i < 5; i++)
rightstep[i] = (w->points[rightv][i] - rightside[i]) / count;
}
if (r_drawflat)
REN_DrawFlatSpan (y);
else
REN_DrawSpan (y);
for (i = 0; i < 5; i++) {
leftside[i] += leftstep[i];
rightside[i] += rightstep[i];
}
y++;
}
}
//=============================================================================
/*
==================
REN_DrawSpanLinear
==================
*/
void
REN_DrawSpanLinear (int y)
{
int x, count;
int ofs;
int tx, ty;
int x1, x2;
float ufrac, vfrac, zfrac, ustep, vstep, zstep;
pixel32_t *in, *out;
float scale;
if (y < 0 || y >= r_height)
return;
x1 = (leftside[0]);
x2 = (rightside[0]);
count = x2 - x1;
if (count < 0)
return;
zfrac = leftside[2];
ufrac = leftside[3];
vfrac = leftside[4];
if (!count)
scale = 1;
else
scale = 1.0 / count;
zstep = (rightside[2] - zfrac) * scale;
ustep = (rightside[3] - ufrac) * scale;
vstep = (rightside[4] - vfrac) * scale;
if (x1 < 0) {
ufrac -= x1 * ustep;
vfrac -= x1 * vstep;
zfrac -= x1 * zstep;
x1 = 0;
}
if (x2 > r_width)
x2 = r_width;
ofs = y * r_width + x1;
for (x = x1; x < x2; x++) {
if (r_zbuffer[ofs] <= zfrac) {
r_zbuffer[ofs] = zfrac;
if (t_widthshift) {
tx = (int) ufrac & t_widthmask;
ty = (int) vfrac & t_heightmask;
in = (pixel32_t *) & t_data[(ty << t_widthshift) + tx];
} else {
tx = (int) (ufrac + t_widthadd) % t_width;
ty = (int) (vfrac + t_heightadd) % t_height;
in = (pixel32_t *) & t_data[ty * t_width + tx];
}
out = (pixel32_t *) & r_picbuffer[ofs];
*out = *in;
}
ufrac += ustep;
vfrac += vstep;
zfrac += zstep;
ofs++;
}
}
/*
=====================
REN_RasterizeFaceLinear
=====================
*/
void
REN_RasterizeFaceLinear (winding_t * w)
{
int y;
int i;
int top, bot;
int leftv, rightv;
int count;
int numvertex;
//
// find top vertex
//
numvertex = w->numpoints;
top = 0x7fffffff;
bot = 0x80000000;
leftv = 0;
for (i = 0; i < numvertex; i++) {
sy[i] = (int) w->points[i][1];
if (sy[i] < top) {
top = sy[i];
leftv = i;
}
if (sy[i] > bot)
bot = sy[i];
}
rightv = leftv;
if (top < 0 || bot > r_height || top > bot)
return; // shouldn't have to have this...
//
// render a trapezoid
//
y = top;
while (y < bot) {
if (y >= sy[leftv]) {
do {
for (i = 0; i < 5; i++)
leftside[i] = w->points[leftv][i];
leftv--;
if (leftv == -1)
leftv = numvertex - 1;
} while (sy[leftv] <= y);
count = sy[leftv] - y;
for (i = 0; i < 5; i++)
leftstep[i] = (w->points[leftv][i] - leftside[i]) / count;
}
if (y >= sy[rightv]) {
do {
for (i = 0; i < 5; i++)
rightside[i] = w->points[rightv][i];
rightv++;
if (rightv == numvertex)
rightv = 0;
} while (sy[rightv] <= y);
count = sy[rightv] - y;
for (i = 0; i < 5; i++)
rightstep[i] = (w->points[rightv][i] - rightside[i]) / count;
}
REN_DrawSpanLinear (y);
for (i = 0; i < 5; i++) {
leftside[i] += leftstep[i];
rightside[i] += rightstep[i];
}
y++;
}
}
//============================================================================
/*
==================
REN_BeginCamera
===================
*/
float r_width_2, r_height_3;
plane_t rfrustum[5];
void
REN_BeginCamera (void)
{
r_width_2 = (float) r_width / 2;
r_height_3 = (float) r_height / 3;
// clip to right side
rfrustum[0].normal[0] = -1;
rfrustum[0].normal[1] = 0;
rfrustum[0].normal[2] = 1;
rfrustum[0].dist = 0;
// clip to left side
rfrustum[1].normal[0] = 1;
rfrustum[1].normal[1] = 0;
rfrustum[1].normal[2] = 1;
rfrustum[1].dist = 0;
// clip to top side
rfrustum[2].normal[0] = 0;
rfrustum[2].normal[1] = -1;
rfrustum[2].normal[2] = r_height_3 / r_width_2;
rfrustum[2].dist = 0;
// clip to bottom side
rfrustum[3].normal[0] = 0;
rfrustum[3].normal[1] = 1;
rfrustum[3].normal[2] = 2 * r_height_3 / r_width_2;
rfrustum[3].dist = 0;
// near Z
rfrustum[4].normal[0] = 0;
rfrustum[4].normal[1] = 0;
rfrustum[4].normal[2] = 1;
rfrustum[4].dist = 1;
}
void
REN_BeginXY (void)
{
rfrustum[0].normal[0] = 1;
rfrustum[0].normal[1] = 0;
rfrustum[0].normal[2] = 0;
rfrustum[0].dist = 0;
rfrustum[1].normal[0] = -1;
rfrustum[1].normal[1] = 0;
rfrustum[1].normal[2] = 0;
rfrustum[1].dist = -r_width;
rfrustum[2].normal[0] = 0;
rfrustum[2].normal[1] = 1;
rfrustum[2].normal[2] = 0;
rfrustum[2].dist = 0;
rfrustum[3].normal[0] = 0;
rfrustum[3].normal[1] = -1;
rfrustum[3].normal[2] = 0;
rfrustum[3].dist = -r_height;
}
/*
=====================
REN_DrawCameraFace
=====================
*/
void
REN_DrawCameraFace (face_t * idpol)
{
int i;
float scale;
int numvertex;
winding_t *w, *in;
vec3_t temp;
if (!idpol->w)
return; // overconstrained plane
r_face = idpol;
//
// back face cull
//
if (DotProduct (r_origin, idpol->plane.normal) <= idpol->plane.dist)
return;
//
// transform in 3D (FIXME: clip first, then transform)
//
in = idpol->w;
numvertex = in->numpoints;
w = NewWinding (numvertex);
w->numpoints = numvertex;
for (i = 0; i < numvertex; i++) {
VectorSubtract (in->points[i], r_origin, temp);
w->points[i][0] = DotProduct (temp, r_matrix[0]);
w->points[i][1] = DotProduct (temp, r_matrix[1]);
w->points[i][2] = DotProduct (temp, r_matrix[2]);
w->points[i][3] = in->points[i][3];
w->points[i][4] = in->points[i][4];
}
//
// 3D clip
//
for (i = 0; i < 4; i++) {
w = ClipWinding (w, &rfrustum[i]);
if (!w)
return;
}
//
// project to 2D
//
for (i = 0; i < w->numpoints; i++) {
scale = r_width_2 / w->points[i][2];
w->points[i][0] = r_width_2 + scale * w->points[i][0];
w->points[i][1] = r_height_3 - scale * w->points[i][1];
w->points[i][2] = scale;
}
//
// draw it
//
REN_SetTexture (idpol);
REN_RasterizeFace (w);
free (w);
}
/*
=====================
REN_DrawXYFace
=====================
*/
void
REN_DrawXYFace (face_t * idpol)
{
int i, j, numvertex;
winding_t *w, *in;
float *dest, *source;
float temp;
if (!idpol->w)
return; // overconstrained plane
w = idpol->w;
r_face = idpol;
//
// back (and side) face cull
//
if (DotProduct (idpol->plane.normal, xy_viewnormal) > -VECTOR_EPSILON)
return;
//
// transform
//
in = idpol->w;
numvertex = in->numpoints;
w = NewWinding (numvertex);
w->numpoints = numvertex;
for (i = 0; i < numvertex; i++) {
// using Z as a scale for the 2D projection
w->points[i][0] = (in->points[i][0] - r_origin[0]) * r_origin[2];
w->points[i][1] =
r_height - (in->points[i][1] - r_origin[1]) * r_origin[2];
w->points[i][2] = in->points[i][2] + 3000;
w->points[i][3] = in->points[i][3];
w->points[i][4] = in->points[i][4];
}
//
// clip
//
for (i = 0; i < 4; i++) {
w = ClipWinding (w, &rfrustum[i]);
if (!w)
return;
}
//
// project to 2D
//
for (i = 0; i < w->numpoints; i++) {
dest = w->points[i];
if (dest[0] < 0)
dest[0] = 0;
if (dest[0] > r_width)
dest[0] = r_width;
if (dest[1] < 0)
dest[1] = 0;
if (dest[1] > r_height)
dest[1] = r_height;
if (xy_viewnormal[2] > 0)
dest[2] = 4096 - dest[2];
}
if (xy_viewnormal[2] > 0) { // flip order when upside down
for (i = 0; i < w->numpoints / 2; i++) {
dest = w->points[i];
source = w->points[w->numpoints - 1 - i];
for (j = 0; j < 5; j++) {
temp = dest[j];
dest[j] = source[j];
source[j] = temp;
}
}
}
REN_SetTexture (idpol);
//
// draw it
//
REN_RasterizeFaceLinear (w);
free (w);
}