#include "rndrlib.h" //#define RETURNERROR(expr) if (error = (expr)) return ret; #define RETURNERROR(code) { error = (code); return; } static RLint inited=0; static RLint error=0; static RLint width=0, height=0, colordepth=0; BITMAP* target=0, *texture=0; static RLint blending=RL_OFF, lighting=RL_OFF; static RLint setupblending=FALSE; static RLint rotationorder=RL_ROTATION_YPR; static RLint matrixmode=0; static RLmatrix transform; static RLint primtype=0; static RLint vertexcount=0; static V3D_f vertices[RL_MAX_VERTICES], *vertexptrs[RL_MAX_VERTICES]; static RLfloat vtx_z[RL_MAX_VERTICES], vtx_w[RL_MAX_VERTICES]; static RLfloat nearz; static RLfloat centerx=0, centery=0; typedef struct RLmatrixstack { RLmatrix matrix; struct RLmatrixstack* down; } RLmatrixstack; static RLmatrixstack*modelview,*projection; static RLmatrixstack** matrixstack; typedef struct RLplanestack { RLplane plane; RLbool snap; struct RLplanestack* down; } RLplanestack; RLplanestack* planestack; /* Other functions */ RLvoid MatrixValues(RLmatrix* dest, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble, RLdouble); RLvoid MatrixCopy(RLmatrix* source, RLmatrix* dest); RLvoid UpdateTransform(); RLvoid ClipVertices(); RLvoid ClipToPlane(RLfloat a, RLfloat b, RLfloat c, RLfloat d);//:-) RLvoid SnapToPlane(RLfloat a, RLfloat b, RLfloat c, RLfloat d); /* :-) */ RLint rlInit() { RLint ret, i; modelview = (RLmatrixstack*)malloc(sizeof(RLmatrixstack)); projection = (RLmatrixstack*)malloc(sizeof(RLmatrixstack)); modelview->down = 0; projection->down = 0; matrixstack = &projection; rlMatrixIdentity(); rlMatrixProject(1, 1, 1); nearz=1; matrixstack = &modelview; inited=1; rlMatrixIdentity(); planestack = NULL; for (i=0; iw; height = target->h; colordepth = bitmap_color_depth(target); centerx = width/2; centery = height/2; } break; case RL_TEXTURE: texture = (BITMAP*)context; break; case RL_NEARPLANE: nearz = (RLfloat)*(RLfloat*)context; break; case RL_BLENDING: blending = value; if (value == RL_ON && setupblending == FALSE) if (colordepth > 8) set_trans_blender(0, 0, 0, 128); else if (colordepth == 8) ; /* Not implemented yet */ break; case RL_MATRIXMODE: if (value == RL_MATRIX_MODELVIEW) matrixstack = &modelview; else if (value == RL_MATRIX_PROJECTION) matrixstack = &projection; break; case RL_LIGHTING: lighting = value; if (value == RL_ON && setupblending == FALSE) if (colordepth > 8) set_trans_blender(0, 0, 0, 128); else if (colordepth == 8) ; /* Not implemented yet */ break; case RL_CENTERX: centerx = value; break; case RL_CENTERY: centery = value; break; } } RLvoid rlMatrixIdentity() { register int i; memset((*matrixstack)->matrix, 0, sizeof(RLmatrixstack)); for (i=0; i<4; i++) (*matrixstack)->matrix[i][i] = 1; UpdateTransform(); } RLvoid rlMatrixValues(RLmatrix* matrix) { memcpy(&(*matrixstack)->matrix, matrix, sizeof(RLmatrix)); UpdateTransform(); } RLvoid rlMatrixAdd(RLmatrix* matrix) { register int i, j; for (i=0; i<4; i++) for (j=0; j<4; j++) (*matrixstack)->matrix[i][j] += (*matrix)[i][j]; UpdateTransform(); } RLvoid rlMatrixMultiply(RLmatrix* matrix) { register int i, j; RLmatrix temp; for (i=0; i<4; i++) for (j=0; j<4; j++) temp[i][j] = (*matrixstack)->matrix[i][0] * (*matrix)[0][j] + (*matrixstack)->matrix[i][1] * (*matrix)[1][j] + (*matrixstack)->matrix[i][2] * (*matrix)[2][j] + (*matrixstack)->matrix[i][3] * (*matrix)[3][j]; MatrixCopy(&temp, &(*matrixstack)->matrix); UpdateTransform(); } RLvoid rlMatrixPush() { RLmatrixstack* temp; temp = (RLmatrixstack*)malloc(sizeof(RLmatrixstack)); temp->down = (*matrixstack); memcpy(&temp->matrix, &(*matrixstack)->matrix, sizeof(RLmatrix)); (*matrixstack) = temp; UpdateTransform(); } RLvoid rlMatrixPop() { RLmatrixstack* temp; temp = (*matrixstack)->down; if (!temp) { error = RL_STACK_LIMIT; return; } free((*matrixstack)); (*matrixstack) = temp; UpdateTransform(); } RLvoid rlMatrixTranslate(RLvector position) { /* This implementation is not the most efficient. * The efficient one would directly manipulate the matrix at the * top of the stack. Instead, we create a translation matrix and * multiply, mostly for instructive purposes. */ RLmatrix translation={0}; register int i; for (i=0; i<4; i++) translation[i][i] = 1; translation[3][0] = position[0]; translation[3][1] = position[1]; translation[3][2] = position[2]; rlMatrixMultiply(&translation); } RLvoid rlMatrixRotate(RLvector orientation) { /* This implementation is not the most efficient. * The efficient one would directly manipulate the matrix at the * top of the stack. Instead, we create a rotation matrix and * multiply repeatedly, mostly for instructive purposes. */ RLmatrix rotation = {0}; if (rotationorder==RL_ROTATION_PYR || rotationorder==RL_ROTATION_PRY) goto doPitch; if (rotationorder==RL_ROTATION_RYP || rotationorder==RL_ROTATION_RPY) goto doRoll; doYaw: MatrixValues(&rotation, cos(orientation[0]), 0, sin(orientation[0]), 0, 0, 1, 0, 0, -sin(orientation[0]), 0, cos(orientation[0]), 0, 0, 0, 0, 1); rlMatrixMultiply(&rotation); if (rotationorder==RL_ROTATION_PYR || rotationorder==RL_ROTATION_YRP) goto doRoll; if (rotationorder==RL_ROTATION_PRY || rotationorder==RL_ROTATION_RPY) goto doDone; doPitch: MatrixValues(&rotation, 1, 0, 0, 0, 0, cos(orientation[1]), sin(orientation[1]), 0, 0, -sin(orientation[1]), cos(orientation[1]), 0, 0, 0, 0, 1); rlMatrixMultiply(&rotation); if (rotationorder==RL_ROTATION_PYR || rotationorder==RL_ROTATION_RPY) goto doYaw; if (rotationorder==RL_ROTATION_YRP || rotationorder==RL_ROTATION_RYP) goto doDone; doRoll: MatrixValues(&rotation, cos(orientation[2]), sin(orientation[2]), 0, 0, -sin(orientation[2]), cos(orientation[2]), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); rlMatrixMultiply(&rotation); if (rotationorder==RL_ROTATION_PRY || rotationorder==RL_ROTATION_RYP) goto doYaw; if (rotationorder==RL_ROTATION_YRP || rotationorder==RL_ROTATION_RPY) goto doPitch; doDone: } RLvoid rlMatrixResize(RLvector scale) { /* This implementation is not the most efficient. * The efficient one would directly manipulate the matrix at the * top of the stack. Instead, we create a resizing matrix and * multiply, mostly for instructive purposes. */ RLmatrix resizing; MatrixValues(&resizing, scale[0], 0, 0, 0, 0, scale[1], 0, 0, 0, 0, scale[2], 0, 0, 0, 0, scale[3]); rlMatrixMultiply(&resizing); } RLvoid rlMatrixProject(RLdouble zoom, RLdouble scale, RLdouble aspect) { /* Normally, you'd have identity loaded before calling this */ RLmatrix projection; MatrixValues(&projection, scale, 0, 0, 0, 0, scale/aspect, 0, 0, 0, 0, 1/zoom, 1/zoom, 0, 0, -1, 0); /* result after homogenization: */ rlMatrixMultiply(&projection); } RLvoid rlBegin(RLenum mode) { primtype = mode; vertexcount = 0; } RLvoid rlColor(RLint color) { if (vertexcount > RL_MAX_VERTICES) RETURNERROR(RL_BUFFER_LIMIT); vertices[vertexcount].c = color; } RLvoid rlTexCoord(RLfloat u, RLfloat v) { if (vertexcount > RL_MAX_VERTICES) RETURNERROR(RL_BUFFER_LIMIT); vertices[vertexcount].u = texture->w * u; vertices[vertexcount].v = texture->h * v; } RLvoid rlVertex(RLvector vertex) { if (vertexcount > RL_MAX_VERTICES) RETURNERROR(RL_BUFFER_LIMIT); vertices[vertexcount].x = vertex[0]; vertices[vertexcount].y = vertex[1]; vertices[vertexcount].z = vertex[2]; vertexcount++; } RLvoid rlEnd() { register int i, j; register float distratio; RLvector temp = {0, 0, 0, 1}, temp2; if (vertexcount <= 0) goto doDone; if (!target) RETURNERROR(RL_MISSING); for (i=0; imatrix[0][j] + temp[1] * modelview->matrix[1][j] + temp[2] * modelview->matrix[2][j] + modelview->matrix[3][j]; vertices[i].x = temp2[0]; vertices[i].y = temp2[1]; vertices[i].z = temp2[2]; } ClipVertices(); for (i=0; imatrix[0][j] + temp[1] * projection->matrix[1][j] + temp[2] * projection->matrix[2][j] + projection->matrix[3][j]; vertices[i].x = centerx + temp2[0]/temp2[3]; vertices[i].y = centery - temp2[1]/temp2[3]; vtx_z[i] = temp2[2]/temp2[3]; vtx_w[i] = temp2[3]; } if (!texture) polygon3d_f(target, POLYTYPE_GRGB, texture, vertexcount, vertexptrs); else { if (lighting == RL_ON) polygon3d_f(target, POLYTYPE_PTEX_LIT, texture, vertexcount, vertexptrs); else polygon3d_f(target, POLYTYPE_PTEX, texture, vertexcount, vertexptrs); } doDone: vertexcount = 0; primtype = 0; } RLvoid rlClipPlanePush(RLdouble a, RLdouble b, RLdouble c, RLdouble d, RLbool snap) { RLplanestack* temp; temp = (RLplanestack*)malloc(sizeof(RLplanestack)); temp->down = planestack; temp->plane.a = a; temp->plane.b = b; temp->plane.c = c; temp->plane.d = d; temp->snap = snap; planestack = temp; } RLvoid rlClipPlanePop() { RLplanestack* temp; if (planestack) { error = RL_STACK_LIMIT; return; } temp = planestack->down; free((planestack)); planestack = temp; } int main() { BITMAP *offscreen; BITMAP *texture; RLvector vector = {-1, -1, 0, 1}; RLvector position = {0, 0, 1}; RLvector orientation = {0, 1, 0}; rlInit(); set_color_depth(16); set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0); offscreen = create_bitmap(640, 480); texture = load_bitmap("tex00.bmp", NULL); //clear_to_color(texture, 255); rlSet(RL_TARGET, 0, offscreen); rlSet(RL_TEXTURE, 0, texture); rlSet(RL_MATRIXMODE, RL_MATRIX_PROJECTION, 0); rlMatrixIdentity(); rlMatrixProject(1, 640, 1); rlSet(RL_MATRIXMODE, RL_MATRIX_MODELVIEW, 0); install_keyboard(); clear(offscreen); while (1) { if (key[KEY_ESC]) break; clear(offscreen); //vector[2]+=0.001; rlMatrixIdentity(); rlMatrixRotate(orientation); rlMatrixTranslate(position); rlBegin(RL_POLYGON); rlTexCoord(0, 0); rlVertex(vector); vector[0] = 1; rlTexCoord(0, 1); rlVertex(vector); vector[1] = 1; rlTexCoord(1, 1); rlVertex(vector); vector[0] = -1; rlTexCoord(1, 0); rlVertex(vector); vector[1] = -1; rlEnd(); blit(offscreen, screen, 0, 0, 0, 0, 640, 480); line (offscreen, rand()%20, rand()%20, rand()%500, rand()%400, 256); vector[0]+=0.01; if (key[KEY_DOWN]) position[2]+=0.1; if (key[KEY_UP]) position[2]-=0.1; if (key[KEY_RIGHT]) orientation[1] = orientation[1]+0.1; } remove_keyboard(); rlExit(); return 0; } RLvoid MatrixValues(RLmatrix* matrix, RLdouble _00, RLdouble _01, RLdouble _02, RLdouble _03, RLdouble _10, RLdouble _11, RLdouble _12, RLdouble _13, RLdouble _20, RLdouble _21, RLdouble _22, RLdouble _23, RLdouble _30, RLdouble _31, RLdouble _32, RLdouble _33) { (*matrix)[0][0] = _00; (*matrix)[0][1] = _01; (*matrix)[0][2] = _02; (*matrix)[0][3] = _03; (*matrix)[1][0] = _10; (*matrix)[1][1] = _11; (*matrix)[1][2] = _12; (*matrix)[1][3] = _13; (*matrix)[2][0] = _20; (*matrix)[2][1] = _21; (*matrix)[2][2] = _22; (*matrix)[2][3] = _23; (*matrix)[3][0] = _30; (*matrix)[3][1] = _31; (*matrix)[3][2] = _32; (*matrix)[3][3] = _33; } RLvoid MatrixCopy(RLmatrix* source, RLmatrix* dest) { register int i, j; if (!dest) dest = (RLmatrix*)malloc(sizeof(RLmatrix)); for (i=0; i<4; i++) for (j=0; j<4; j++) (*dest)[i][j] = (*source)[i][j]; } RLvoid UpdateTransform() { register int i, j; RLmatrix temp; if (!inited) return; MatrixCopy(&modelview->matrix, &transform); for (i=0; i<4; i++) for (j=0; j<4; j++) temp[i][j] = transform[i][0] * projection->matrix[0][j] + transform[i][1] * projection->matrix[1][j] + transform[i][2] * projection->matrix[2][j] + transform[i][3] * projection->matrix[3][j]; MatrixCopy(&temp, &transform); } RLvoid ClipVertices() { RLplanestack* plane; /* Clip vertices to z plane */ ClipToPlane(0, 0, 1, -nearz); /* Clip vertices to user-defined planes */ plane = planestack; while (plane) { if (plane->snap) SnapToPlane(plane->plane.a, plane->plane.b, plane->plane.c, plane->plane.d); else ClipToPlane(plane->plane.a, plane->plane.b, plane->plane.c, plane->plane.d); } } RLvoid ClipToPlane(RLfloat a, RLfloat b, RLfloat c, RLfloat d)//:-) { register int i, ii, j=0; RLfloat dist1, dist2, distratio; static V3D_f temp[16]; for (i=0; i=0 && dist2>=0) // line unclipped and visible { vertices[j] = temp[i]; j++; } else // line partially visible if (dist1>0) // first vertex is visible { distratio = dist1/(dist1-dist2); vertices[j] = temp[i]; j++; // Copied 1st vertex vertices[j].x = temp[i].x + (temp[ii].x - temp[i].x) * distratio; vertices[j].y = temp[i].y + (temp[ii].y - temp[i].y) * distratio; vertices[j].z = temp[i].z + (temp[ii].z - temp[i].z) * distratio; vertices[j].u = temp[i].u + (temp[ii].u - temp[i].u) * distratio; vertices[j].v = temp[i].v + (temp[ii].v - temp[i].v) * distratio; vertices[j].c = (int)(temp[i].c + (temp[ii].c - temp[i].c) * distratio); j++; // Copied second vertex } else // second vertex is visible { distratio = dist2/(dist2-dist1); vertices[j].x = temp[ii].x + (temp[i].x - temp[ii].x) * distratio; vertices[j].y = temp[ii].y + (temp[i].y - temp[ii].y) * distratio; vertices[j].z = temp[ii].z + (temp[i].z - temp[ii].z) * distratio; vertices[j].u = temp[ii].u + (temp[i].u - temp[ii].u) * distratio; vertices[j].v = temp[ii].v + (temp[i].v - temp[ii].v) * distratio; vertices[j].c = (int)(temp[ii].c + (temp[i].c - temp[ii].c) * distratio); j++; // Copy only first vertex. 2nd vertex will be copied // in next iteration of loop } } vertexcount = j; } RLvoid SnapToPlane(RLfloat a, RLfloat b, RLfloat c, RLfloat d) /* :-) */ { RLbool snapped=1; register int i, ii, j=0; RLfloat dist1, dist2, distratio; dist2 = a * vertices[0].x + b * vertices[0].y + c * vertices[0].z + d; for (i=0, j=0; i