//----------------------------------------------------------------------------- // Torque Game Engine // Quake GL DirectX wrapper //----------------------------------------------------------------------------- #include "opengl2d3d/glu2d3d.h" GLAPI BOOL GLAPIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { hModule; lpReserved; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } extern "C" { GLAPI const GLubyte* GLAPIENTRY gluErrorString(GLenum errorCode) { /* GLU Errors */ if (errorCode == GLU_NO_ERROR) { return (GLubyte *) "no error"; } else if (errorCode == GLU_INVALID_ENUM) { return (GLubyte *) "invalid enum"; } else if (errorCode == GLU_INVALID_VALUE) { return (GLubyte *) "invalid value"; } else if (errorCode == GLU_OUT_OF_MEMORY) { return (GLubyte *) "out of memory"; } else { return NULL; } } GLAPI const GLubyte* GLAPIENTRY gluGetString(GLenum name) { static char *extensions = ""; static char *version = "1.0 GarageGames"; switch (name) { case GLU_EXTENSIONS: return (GLubyte *) extensions; case GLU_VERSION: return (GLubyte *) version; default: return NULL; } } GLAPI void GLAPIENTRY gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top) { glOrtho(left, right, bottom, top, -1.0, 1.0); } GLAPI void GLAPIENTRY gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) { GLdouble xmin, xmax, ymin, ymax; ymax = zNear * tan(fovy * M_PI / 360.0); ymin = -ymax; xmin = ymin * aspect; xmax = ymax * aspect; glFrustum(xmin, xmax, ymin, ymax, zNear, zFar); } GLAPI void GLAPIENTRY gluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height, const GLint viewport[4]) { GLfloat m[16]; GLfloat sx, sy; GLfloat tx, ty; sx = (GLfloat) (viewport[2] / width); sy = (GLfloat) (viewport[3] / height); tx = (GLfloat) ((viewport[2] + 2.0 * (viewport[0] - x)) / width); ty = (GLfloat) ((viewport[3] + 2.0 * (viewport[1] - y)) / height); #define M(row,col) m[col*4+row] M(0, 0) = sx; M(0, 1) = 0.0; M(0, 2) = 0.0; M(0, 3) = tx; M(1, 0) = 0.0; M(1, 1) = sy; M(1, 2) = 0.0; M(1, 3) = ty; M(2, 0) = 0.0; M(2, 1) = 0.0; M(2, 2) = 1.0; M(2, 3) = 0.0; M(3, 0) = 0.0; M(3, 1) = 0.0; M(3, 2) = 0.0; M(3, 3) = 1.0; #undef M glMultMatrixf(m); } GLAPI void GLAPIENTRY gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz) { GLdouble m[16]; GLdouble x[3], y[3], z[3]; GLdouble mag; /* Make rotation matrix */ /* Z vector */ z[0] = eyex - centerx; z[1] = eyey - centery; z[2] = eyez - centerz; mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); if (mag) { /* mpichler, 19950515 */ z[0] /= mag; z[1] /= mag; z[2] /= mag; } /* Y vector */ y[0] = upx; y[1] = upy; y[2] = upz; /* X vector = Y cross Z */ x[0] = y[1] * z[2] - y[2] * z[1]; x[1] = -y[0] * z[2] + y[2] * z[0]; x[2] = y[0] * z[1] - y[1] * z[0]; /* Recompute Y = Z cross X */ y[0] = z[1] * x[2] - z[2] * x[1]; y[1] = -z[0] * x[2] + z[2] * x[0]; y[2] = z[0] * x[1] - z[1] * x[0]; /* mpichler, 19950515 */ /* cross product gives area of parallelogram, which is < 1.0 for * non-perpendicular unit-length vectors; so normalize x, y here */ mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); if (mag) { x[0] /= mag; x[1] /= mag; x[2] /= mag; } mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); if (mag) { y[0] /= mag; y[1] /= mag; y[2] /= mag; } #define M(row,col) m[col*4+row] M(0, 0) = x[0]; M(0, 1) = x[1]; M(0, 2) = x[2]; M(0, 3) = 0.0; M(1, 0) = y[0]; M(1, 1) = y[1]; M(1, 2) = y[2]; M(1, 3) = 0.0; M(2, 0) = z[0]; M(2, 1) = z[1]; M(2, 2) = z[2]; M(2, 3) = 0.0; M(3, 0) = 0.0; M(3, 1) = 0.0; M(3, 2) = 0.0; M(3, 3) = 1.0; #undef M glMultMatrixd(m); /* Translate Eye to Origin */ glTranslated(-eyex, -eyey, -eyez); } /* * Transform a point (column vector) by a 4x4 matrix. I.e. out = m * in * Input: m - the 4x4 matrix * in - the 4x1 vector * Output: out - the resulting 4x1 vector. */ static void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4]) { #define M(row,col) m[col*4+row] out[0] = M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3]; out[1] = M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3]; out[2] = M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3]; out[3] = M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3]; #undef M } /* * Perform a 4x4 matrix multiplication (product = a x b). * Input: a, b - matrices to multiply * Output: product - product of a and b */ static void matmul(GLdouble * product, const GLdouble * a, const GLdouble * b) { /* This matmul was contributed by Thomas Malik */ GLdouble temp[16]; GLint i; #define A(row,col) a[(col<<2)+row] #define B(row,col) b[(col<<2)+row] #define T(row,col) temp[(col<<2)+row] /* i-te Zeile */ for (i = 0; i < 4; i++) { T(i, 0) = A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i, 3) * B(3, 0); T(i, 1) = A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i, 3) * B(3, 1); T(i, 2) = A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i, 3) * B(3, 2); T(i, 3) = A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i, 3) * B(3, 3); } #undef A #undef B #undef T memcpy(product, temp, 16 * sizeof(GLdouble)); } /* * Compute inverse of 4x4 transformation matrix. * Code contributed by Jacques Leroy jle@star.be * Return GL_TRUE for success, GL_FALSE for failure (singular matrix) */ static GLboolean invert_matrix(const GLdouble * m, GLdouble * out) { /* NB. OpenGL Matrices are COLUMN major. */ #define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; } #define MAT(m,r,c) (m)[(c)*4+(r)] GLdouble wtmp[4][8]; GLdouble m0, m1, m2, m3, s; GLdouble *r0, *r1, *r2, *r3; r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1), r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3), r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1), r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3), r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1), r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3), r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1), r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3), r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; /* choose pivot - or die */ if (fabs(r3[0]) > fabs(r2[0])) SWAP_ROWS(r3, r2); if (fabs(r2[0]) > fabs(r1[0])) SWAP_ROWS(r2, r1); if (fabs(r1[0]) > fabs(r0[0])) SWAP_ROWS(r1, r0); if (0.0 == r0[0]) return GL_FALSE; /* eliminate first variable */ m1 = r1[0] / r0[0]; m2 = r2[0] / r0[0]; m3 = r3[0] / r0[0]; s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; s = r0[4]; if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } s = r0[5]; if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } s = r0[6]; if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } s = r0[7]; if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } /* choose pivot - or die */ if (fabs(r3[1]) > fabs(r2[1])) SWAP_ROWS(r3, r2); if (fabs(r2[1]) > fabs(r1[1])) SWAP_ROWS(r2, r1); if (0.0 == r1[1]) return GL_FALSE; /* eliminate second variable */ m2 = r2[1] / r1[1]; m3 = r3[1] / r1[1]; r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } /* choose pivot - or die */ if (fabs(r3[2]) > fabs(r2[2])) SWAP_ROWS(r3, r2); if (0.0 == r2[2]) return GL_FALSE; /* eliminate third variable */ m3 = r3[2] / r2[2]; r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7]; /* last check */ if (0.0 == r3[3]) return GL_FALSE; s = 1.0 / r3[3]; /* now back substitute row 3 */ r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; m2 = r2[3]; /* now back substitute row 2 */ s = 1.0 / r2[2]; r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); m1 = r1[3]; r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; m0 = r0[3]; r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; m1 = r1[2]; /* now back substitute row 1 */ s = 1.0 / r1[1]; r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); m0 = r0[2]; r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; m0 = r0[1]; /* now back substitute row 0 */ s = 1.0 / r0[0]; r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); MAT(out, 0, 0) = r0[4]; MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6]; MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4]; MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6]; MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4]; MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6]; MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4]; MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6]; MAT(out, 3, 3) = r3[7]; return GL_TRUE; #undef MAT #undef SWAP_ROWS } /* projection du point (objx,objy,obz) sur l'ecran (winx,winy,winz) */ GLAPI GLint GLAPIENTRY gluProject(GLdouble objx, GLdouble objy, GLdouble objz, const GLdouble model[16], const GLdouble proj[16], const GLint viewport[4], GLdouble * winx, GLdouble * winy, GLdouble * winz) { /* matrice de transformation */ GLdouble in[4], out[4]; /* initilise la matrice et le vecteur a transformer */ in[0] = objx; in[1] = objy; in[2] = objz; in[3] = 1.0; transform_point(out, model, in); transform_point(in, proj, out); /* d'ou le resultat normalise entre -1 et 1 */ if (in[3] == 0.0) return GL_FALSE; in[0] /= in[3]; in[1] /= in[3]; in[2] /= in[3]; /* en coordonnees ecran */ *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2; *winy = viewport[1] + (1 + in[1]) * viewport[3] / 2; /* entre 0 et 1 suivant z */ *winz = (1 + in[2]) / 2; return GL_TRUE; } /* transformation du point ecran (winx,winy,winz) en point objet */ GLAPI GLint GLAPIENTRY gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble model[16], const GLdouble proj[16], const GLint viewport[4], GLdouble * objx, GLdouble * objy, GLdouble * objz) { /* matrice de transformation */ GLdouble m[16], A[16]; GLdouble in[4], out[4]; /* transformation coordonnees normalisees entre -1 et 1 */ in[0] = (winx - viewport[0]) * 2 / viewport[2] - 1.0; in[1] = (winy - viewport[1]) * 2 / viewport[3] - 1.0; in[2] = 2 * winz - 1.0; in[3] = 1.0; /* calcul transformation inverse */ matmul(A, proj, model); invert_matrix(A, m); /* d'ou les coordonnees objets */ transform_point(out, m, in); if (out[3] == 0.0) return GL_FALSE; *objx = out[0] / out[3]; *objy = out[1] / out[3]; *objz = out[2] / out[3]; return GL_TRUE; } GLAPI GLint GLAPIENTRY gluScaleImage(GLenum format, GLsizei widthin, GLsizei heightin, GLenum typein, const void *datain, GLsizei widthout, GLsizei heightout, GLenum typeout, void *dataout) { GLint components, i, j, k; GLfloat *tempin, *tempout; GLfloat sx, sy; GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels; GLint packrowlength, packalignment, packskiprows, packskippixels; GLint sizein, sizeout; GLint rowstride, rowlen; /* Determine number of components per pixel */ switch (format) { case GL_COLOR_INDEX: case GL_STENCIL_INDEX: case GL_DEPTH_COMPONENT: case GL_RED: case GL_GREEN: case GL_BLUE: case GL_ALPHA: case GL_LUMINANCE: components = 1; break; case GL_LUMINANCE_ALPHA: components = 2; break; case GL_RGB: case GL_BGR: components = 3; break; case GL_RGBA: case GL_BGRA: #ifdef GL_EXT_abgr case GL_ABGR_EXT: #endif components = 4; break; default: return GLU_INVALID_ENUM; } /* Determine bytes per input datum */ switch (typein) { case GL_UNSIGNED_BYTE: sizein = sizeof(GLubyte); break; case GL_BYTE: sizein = sizeof(GLbyte); break; case GL_UNSIGNED_SHORT: sizein = sizeof(GLushort); break; case GL_SHORT: sizein = sizeof(GLshort); break; case GL_UNSIGNED_INT: sizein = sizeof(GLuint); break; case GL_INT: sizein = sizeof(GLint); break; case GL_FLOAT: sizein = sizeof(GLfloat); break; case GL_BITMAP: /* not implemented yet */ default: return GL_INVALID_ENUM; } /* Determine bytes per output datum */ switch (typeout) { case GL_UNSIGNED_BYTE: sizeout = sizeof(GLubyte); break; case GL_BYTE: sizeout = sizeof(GLbyte); break; case GL_UNSIGNED_SHORT: sizeout = sizeof(GLushort); break; case GL_SHORT: sizeout = sizeof(GLshort); break; case GL_UNSIGNED_INT: sizeout = sizeof(GLuint); break; case GL_INT: sizeout = sizeof(GLint); break; case GL_FLOAT: sizeout = sizeof(GLfloat); break; case GL_BITMAP: /* not implemented yet */ default: return GL_INVALID_ENUM; } /* Get glPixelStore state */ glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackrowlength); glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackalignment); glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpackskiprows); glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpackskippixels); glGetIntegerv(GL_PACK_ROW_LENGTH, &packrowlength); glGetIntegerv(GL_PACK_ALIGNMENT, &packalignment); glGetIntegerv(GL_PACK_SKIP_ROWS, &packskiprows); glGetIntegerv(GL_PACK_SKIP_PIXELS, &packskippixels); /* Allocate storage for intermediate images */ tempin = (GLfloat *) malloc(widthin * heightin * components * sizeof(GLfloat)); if (!tempin) { return GLU_OUT_OF_MEMORY; } tempout = (GLfloat *) malloc(widthout * heightout * components * sizeof(GLfloat)); if (!tempout) { free(tempin); return GLU_OUT_OF_MEMORY; } /* * Unpack the pixel data and convert to floating point */ if (unpackrowlength > 0) { rowlen = unpackrowlength; } else { rowlen = widthin; } if (sizein >= unpackalignment) { rowstride = components * rowlen; } else { rowstride = unpackalignment / sizein * CEILING(components * rowlen * sizein, unpackalignment); } switch (typein) { case GL_UNSIGNED_BYTE: k = 0; for (i = 0; i < heightin; i++) { GLubyte *ubptr = (GLubyte *) datain + i * rowstride + unpackskiprows * rowstride + unpackskippixels * components; for (j = 0; j < widthin * components; j++) { dummy(j, k); tempin[k++] = (GLfloat) * ubptr++; } } break; case GL_BYTE: k = 0; for (i = 0; i < heightin; i++) { GLbyte *bptr = (GLbyte *) datain + i * rowstride + unpackskiprows * rowstride + unpackskippixels * components; for (j = 0; j < widthin * components; j++) { dummy(j, k); tempin[k++] = (GLfloat) * bptr++; } } break; case GL_UNSIGNED_SHORT: k = 0; for (i = 0; i < heightin; i++) { GLushort *usptr = (GLushort *) datain + i * rowstride + unpackskiprows * rowstride + unpackskippixels * components; for (j = 0; j < widthin * components; j++) { dummy(j, k); tempin[k++] = (GLfloat) * usptr++; } } break; case GL_SHORT: k = 0; for (i = 0; i < heightin; i++) { GLshort *sptr = (GLshort *) datain + i * rowstride + unpackskiprows * rowstride + unpackskippixels * components; for (j = 0; j < widthin * components; j++) { dummy(j, k); tempin[k++] = (GLfloat) * sptr++; } } break; case GL_UNSIGNED_INT: k = 0; for (i = 0; i < heightin; i++) { GLuint *uiptr = (GLuint *) datain + i * rowstride + unpackskiprows * rowstride + unpackskippixels * components; for (j = 0; j < widthin * components; j++) { dummy(j, k); tempin[k++] = (GLfloat) * uiptr++; } } break; case GL_INT: k = 0; for (i = 0; i < heightin; i++) { GLint *iptr = (GLint *) datain + i * rowstride + unpackskiprows * rowstride + unpackskippixels * components; for (j = 0; j < widthin * components; j++) { dummy(j, k); tempin[k++] = (GLfloat) * iptr++; } } break; case GL_FLOAT: k = 0; for (i = 0; i < heightin; i++) { GLfloat *fptr = (GLfloat *) datain + i * rowstride + unpackskiprows * rowstride + unpackskippixels * components; for (j = 0; j < widthin * components; j++) { dummy(j, k); tempin[k++] = *fptr++; } } break; default: return GLU_INVALID_ENUM; } /* * Scale the image! */ if (widthout > 1) sx = (GLfloat) (widthin - 1) / (GLfloat) (widthout - 1); else sx = (GLfloat) (widthin - 1); if (heightout > 1) sy = (GLfloat) (heightin - 1) / (GLfloat) (heightout - 1); else sy = (GLfloat) (heightin - 1); /*#define POINT_SAMPLE*/ #ifdef POINT_SAMPLE for (i = 0; i < heightout; i++) { GLint ii = i * sy; for (j = 0; j < widthout; j++) { GLint jj = j * sx; GLfloat *src = tempin + (ii * widthin + jj) * components; GLfloat *dst = tempout + (i * widthout + j) * components; for (k = 0; k < components; k++) { *dst++ = *src++; } } } #else if (sx < 1.0 && sy < 1.0) { /* magnify both width and height: use weighted sample of 4 pixels */ GLint i0, i1, j0, j1; GLfloat alpha, beta; GLfloat *src00, *src01, *src10, *src11; GLfloat s1, s2; GLfloat *dst; for (i = 0; i < heightout; i++) { i0 = (GLint) (i * sy); i1 = i0 + 1; if (i1 >= heightin) i1 = heightin - 1; /* i1 = (i+1) * sy - EPSILON;*/ alpha = i * sy - i0; for (j = 0; j < widthout; j++) { j0 = (GLint) (j * sx); j1 = j0 + 1; if (j1 >= widthin) j1 = widthin - 1; /* j1 = (j+1) * sx - EPSILON; */ beta = j * sx - j0; /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */ src00 = tempin + (i0 * widthin + j0) * components; src01 = tempin + (i0 * widthin + j1) * components; src10 = tempin + (i1 * widthin + j0) * components; src11 = tempin + (i1 * widthin + j1) * components; dst = tempout + (i * widthout + j) * components; for (k = 0; k < components; k++) { s1 = (GLfloat) (*src00++ * (1.0 - beta) + *src01++ * beta); s2 = (GLfloat) (*src10++ * (1.0 - beta) + *src11++ * beta); *dst++ = (GLfloat) (s1 * (1.0 - alpha) + s2 * alpha); } } } } else { /* shrink width and/or height: use an unweighted box filter */ GLint i0, i1; GLint j0, j1; GLint ii, jj; GLfloat sum, *dst; for (i = 0; i < heightout; i++) { i0 = (GLint) (i * sy); i1 = i0 + 1; if (i1 >= heightin) i1 = heightin - 1; /* i1 = (i+1) * sy - EPSILON; */ for (j = 0; j < widthout; j++) { j0 = (GLint) (j * sx); j1 = j0 + 1; if (j1 >= widthin) j1 = widthin - 1; /* j1 = (j+1) * sx - EPSILON; */ dst = tempout + (i * widthout + j) * components; /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */ for (k = 0; k < components; k++) { sum = 0.0; for (ii = i0; ii <= i1; ii++) { for (jj = j0; jj <= j1; jj++) { sum += *(tempin + (ii * widthin + jj) * components + k); } } sum /= (j1 - j0 + 1) * (i1 - i0 + 1); *dst++ = sum; } } } } #endif /* * Return output image */ if (packrowlength > 0) { rowlen = packrowlength; } else { rowlen = widthout; } if (sizeout >= packalignment) { rowstride = components * rowlen; } else { rowstride = packalignment / sizeout * CEILING(components * rowlen * sizeout, packalignment); } switch (typeout) { case GL_UNSIGNED_BYTE: k = 0; for (i = 0; i < heightout; i++) { GLubyte *ubptr = (GLubyte *) dataout + i * rowstride + packskiprows * rowstride + packskippixels * components; for (j = 0; j < widthout * components; j++) { dummy(j, k + i); *ubptr++ = (GLubyte) tempout[k++]; } } break; case GL_BYTE: k = 0; for (i = 0; i < heightout; i++) { GLbyte *bptr = (GLbyte *) dataout + i * rowstride + packskiprows * rowstride + packskippixels * components; for (j = 0; j < widthout * components; j++) { dummy(j, k + i); *bptr++ = (GLbyte) tempout[k++]; } } break; case GL_UNSIGNED_SHORT: k = 0; for (i = 0; i < heightout; i++) { GLushort *usptr = (GLushort *) dataout + i * rowstride + packskiprows * rowstride + packskippixels * components; for (j = 0; j < widthout * components; j++) { dummy(j, k + i); *usptr++ = (GLushort) tempout[k++]; } } break; case GL_SHORT: k = 0; for (i = 0; i < heightout; i++) { GLshort *sptr = (GLshort *) dataout + i * rowstride + packskiprows * rowstride + packskippixels * components; for (j = 0; j < widthout * components; j++) { dummy(j, k + i); *sptr++ = (GLshort) tempout[k++]; } } break; case GL_UNSIGNED_INT: k = 0; for (i = 0; i < heightout; i++) { GLuint *uiptr = (GLuint *) dataout + i * rowstride + packskiprows * rowstride + packskippixels * components; for (j = 0; j < widthout * components; j++) { dummy(j, k + i); *uiptr++ = (GLuint) tempout[k++]; } } break; case GL_INT: k = 0; for (i = 0; i < heightout; i++) { GLint *iptr = (GLint *) dataout + i * rowstride + packskiprows * rowstride + packskippixels * components; for (j = 0; j < widthout * components; j++) { dummy(j, k + i); *iptr++ = (GLint) tempout[k++]; } } break; case GL_FLOAT: k = 0; for (i = 0; i < heightout; i++) { GLfloat *fptr = (GLfloat *) dataout + i * rowstride + packskiprows * rowstride + packskippixels * components; for (j = 0; j < widthout * components; j++) { dummy(j, k + i); *fptr++ = tempout[k++]; } } break; default: return GLU_INVALID_ENUM; } /* free temporary image storage */ free(tempin); free(tempout); return 0; } /* * Return the largest k such that 2^k <= n. */ static GLint ilog2(GLint n) { GLint k; if (n <= 0) return 0; for (k = 0; n >>= 1; k++) {} return k; } /* * Find the value nearest to n which is also a power of two. */ static GLint round2(GLint n) { GLint m; for (m = 1; m < n; m *= 2) {} /* m>=n */ if (m - n <= n - m / 2) { return m; } else { return m / 2; } } /* * WARNING: This function isn't finished and has never been tested!!!! */ GLAPI GLint GLAPIENTRY gluBuild1DMipmaps(GLenum target, GLint components, GLsizei width, GLenum format, GLenum type, const void *data) { target; GLubyte *texture; GLint levels, max_levels; GLint new_width, max_width; GLint i, j, k, l; if (width < 1) return GLU_INVALID_VALUE; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_width); max_levels = ilog2(max_width) + 1; /* Compute how many mipmap images to make */ levels = ilog2(width) + 1; if (levels > max_levels) { levels = max_levels; } new_width = 1 << (levels - 1); texture = (GLubyte *) malloc(new_width * components); if (!texture) { return GLU_OUT_OF_MEMORY; } if (width != new_width) { /* initial rescaling */ switch (type) { case GL_UNSIGNED_BYTE: { GLubyte *ub_data = (GLubyte *) data; for (i = 0; i < new_width; i++) { j = i * width / new_width; for (k = 0; k < components; k++) { texture[i * components + k] = ub_data[j * components + k]; } } } break; default: /* Not implemented */ return GLU_ERROR; } } /* generate and load mipmap images */ for (l = 0; l < levels; l++) { glTexImage1D(GL_TEXTURE_1D, l, components, new_width, 0, format, GL_UNSIGNED_BYTE, texture); /* Scale image down to 1/2 size */ new_width = new_width / 2; for (i = 0; i < new_width; i++) { for (k = 0; k < components; k++) { GLint sample1, sample2; sample1 = (GLint) texture[i * 2 * components + k]; sample2 = (GLint) texture[(i * 2 + 1) * components + k]; texture[i * components + k] = (GLubyte) ((sample1 + sample2) / 2); } } } free(texture); return 0; } /* * Given an pixel format and datatype, return the number of bytes to * store one pixel. */ static GLint bytes_per_pixel(GLenum format, GLenum type) { GLint n, m; switch (format) { case GL_COLOR_INDEX: case GL_STENCIL_INDEX: case GL_DEPTH_COMPONENT: case GL_RED: case GL_GREEN: case GL_BLUE: case GL_ALPHA: case GL_LUMINANCE: n = 1; break; case GL_LUMINANCE_ALPHA: n = 2; break; case GL_RGB: case GL_BGR: n = 3; break; case GL_RGBA: case GL_BGRA: #ifdef GL_EXT_abgr case GL_ABGR_EXT: #endif n = 4; break; default: n = 0; } switch (type) { case GL_UNSIGNED_BYTE: m = sizeof(GLubyte); break; case GL_BYTE: m = sizeof(GLbyte); break; case GL_BITMAP: m = 1; break; case GL_UNSIGNED_SHORT: m = sizeof(GLushort); break; case GL_SHORT: m = sizeof(GLshort); break; case GL_UNSIGNED_INT: m = sizeof(GLuint); break; case GL_INT: m = sizeof(GLint); break; case GL_FLOAT: m = sizeof(GLfloat); break; default: m = 0; } return n * m; } GLAPI GLint GLAPIENTRY gluBuild2DMipmaps(GLenum target, GLint components, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data) { GLint w, h, maxsize; void *image, *newimage; GLint neww, newh, level, bpp; int error; GLboolean done; GLint retval = 0; GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels; GLint packrowlength, packalignment, packskiprows, packskippixels; if (width < 1 || height < 1) return GLU_INVALID_VALUE; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); w = round2(width); if (w > maxsize) { w = maxsize; } h = round2(height); if (h > maxsize) { h = maxsize; } bpp = bytes_per_pixel(format, type); if (bpp == 0) { /* probably a bad format or type enum */ return GLU_INVALID_ENUM; } /* Get current glPixelStore values */ glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackrowlength); glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackalignment); glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpackskiprows); glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpackskippixels); glGetIntegerv(GL_PACK_ROW_LENGTH, &packrowlength); glGetIntegerv(GL_PACK_ALIGNMENT, &packalignment); glGetIntegerv(GL_PACK_SKIP_ROWS, &packskiprows); glGetIntegerv(GL_PACK_SKIP_PIXELS, &packskippixels); /* set pixel packing */ glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); done = GL_FALSE; if (w != width || h != height) { /* must rescale image to get "top" mipmap texture image */ image = malloc((w + 4) * h * bpp); if (!image) { return GLU_OUT_OF_MEMORY; } error = gluScaleImage(format, width, height, type, data, w, h, type, image); if (error) { retval = error; done = GL_TRUE; } } else { image = (void *) data; } level = 0; while (!done) { if (image != data) { /* set pixel unpacking */ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); } glTexImage2D(target, level, components, w, h, 0, format, type, image); if (w == 1 && h == 1) break; neww = (w < 2) ? 1 : w / 2; newh = (h < 2) ? 1 : h / 2; newimage = malloc((neww + 4) * newh * bpp); if (!newimage) { return GLU_OUT_OF_MEMORY; } error = gluScaleImage(format, w, h, type, image, neww, newh, type, newimage); if (error) { retval = error; done = GL_TRUE; } if (image != data) { free(image); } image = newimage; w = neww; h = newh; level++; } if (image != data) { free(image); } /* Restore original glPixelStore state */ glPixelStorei(GL_UNPACK_ROW_LENGTH, unpackrowlength); glPixelStorei(GL_UNPACK_ALIGNMENT, unpackalignment); glPixelStorei(GL_UNPACK_SKIP_ROWS, unpackskiprows); glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpackskippixels); glPixelStorei(GL_PACK_ROW_LENGTH, packrowlength); glPixelStorei(GL_PACK_ALIGNMENT, packalignment); glPixelStorei(GL_PACK_SKIP_ROWS, packskiprows); glPixelStorei(GL_PACK_SKIP_PIXELS, packskippixels); return retval; } }