/******************************Module*Header*******************************\ * Module Name: genlem.c * * The Twist style of the 3D Flying Objects screen saver. * * Solid model of a 3D lemniscate. * * Copyright (c) 1994-1995 Microsoft Corporation * \**************************************************************************/ #include #include #include #include #include #include "ssopengl.h" #include "mesh.h" #define ROT_PREC 10 #define NORMS(x, y) lemMesh.norms[((x) * iPrec) + y] #define GRID(x, y) lemMesh.pts[((x) * iPrec) + y] static MESH lemMesh; static POINT3D basis[ROT_PREC]; static double zrot = 0.2; static int iPrec = 32; static double *lemX; static double *lemY; static double *lemXT; static double *lemYT; static void getLem(double index, double max, double *angle, double *r) { double a; a = (index * PI) / (max - 1.0); if (a >= PI) a -= PI; if (a > PI / 2.0) { *angle = (2.0 * PI) - a; *r = 0.5 * sqrt(sin(2.0 * *angle)); } else { *angle = a; *r = 0.5 * sqrt(sin(2.0 * *angle)); } } static void initLemCoords(int iMax) { int i; double max = (double)iMax; double angle; double r; for (i = 0; i < iMax; i++) { getLem((double)i, (double)iPrec, &angle, &r); lemX[i] = r * cos(angle); lemY[i] = r * sin(angle); getLem((double)i + 0.00001, (double)iPrec, &angle, &r); lemXT[i] = r * cos(angle); lemYT[i] = r * sin(angle); } } void genLemniscate(void) { int i; int j; double posInc = 2.0 / (float)iPrec; int facecount = 0; int ptcount = 0; POINT3D norm; static float twistFact = 0.0f; static float twistFactAdd = 0.05f; POINT3D a[ROT_PREC]; POINT3D b[ROT_PREC]; MATRIX matrix; MESH *mesh = &lemMesh; mesh->numPoints = 0; mesh->numFaces = 0; for (i = 0; i < (iPrec - 1) * (ROT_PREC - 1); i++) mesh->norms[i] = ptZero; for (i = 0; i < (iPrec - 1); i++) { double x1, y1, x2, y2; double len; double sinAngle; double rotZ; int id[4]; x1 = lemX[i]; y1 = lemY[i]; x2 = lemXT[i]; y2 = lemYT[i]; x2 -= x1; y2 -= y1; len = sqrt(x2 * x2 + y2 * y2); if (len > 0.0) sinAngle = y2 / len; else sinAngle = 0.0; if (y2 < 0.0) sinAngle = -sinAngle; rotZ = asin(sinAngle); if (x2 < 0.0) rotZ = PI - rotZ; if (y2 < 0.0) rotZ = -rotZ; if (rotZ < 0.0) rotZ = 2.0 * PI + rotZ; matrixIdent(&matrix); matrixRotate(&matrix, 0.0, 0.0, -rotZ); matrixTranslate(&matrix, x1, y1, twistFact * cos((2.0 * PI * (float)i) / ((float)iPrec - 1))); for (j = 0; j < ROT_PREC; j++) xformPoint(&a[j], &basis[j], &matrix); x1 = lemX[i+1]; y1 = lemY[i+1]; x2 = lemXT[i+1]; y2 = lemYT[i+1]; x2 -= x1; y2 -= y1; len = sqrt(x2 * x2 + y2 * y2); if (len > 0.0) sinAngle = y2 / len; else sinAngle = 0.0; if (y2 < 0.0) sinAngle = -sinAngle; rotZ = asin(sinAngle); if (x2 < 0.0) rotZ = PI - rotZ; if (y2 < 0.0) rotZ = -rotZ; if (rotZ < 0.0) rotZ = 2.0 * PI + rotZ; matrixIdent(&matrix); matrixRotate(&matrix, 0.0, 0.0, -rotZ); matrixTranslate(&matrix, x1, y1, twistFact * cos((2.0 * PI * ((float)i + 1.0)) / ((float)iPrec - 1))); for (j = 0; j < ROT_PREC; j++) xformPoint(&b[j], &basis[j], &matrix); memcpy(&mesh->pts[ptcount], &a, sizeof(POINT3D) * (ROT_PREC - 1)); ptcount += (ROT_PREC - 1); mesh->numPoints += (ROT_PREC - 1); for (j = 0; j < (ROT_PREC - 1); j++) { int k; int jj; if (j == (ROT_PREC - 2)) jj = 0; else jj = j + 1; calcNorm(&norm, &b[j + 1], &b[j], &a[j]); mesh->faces[facecount].material = 3; mesh->faces[facecount].norm = norm; if (i == iPrec - 2) { id[0] = mesh->faces[facecount].p[0] = j; id[1] = mesh->faces[facecount].p[1] = jj; } else { id[0] = mesh->faces[facecount].p[0] = ptcount + j; id[1] = mesh->faces[facecount].p[1] = ptcount + jj; } id[2] = mesh->faces[facecount].p[2] = ptcount - (ROT_PREC - 1) + j; id[3] = mesh->faces[facecount].p[3] = ptcount - (ROT_PREC - 1) + jj; for (k = 0; k < 4; k++) { POINT3D *pn = &mesh->norms[id[k]]; pn->x += norm.x; pn->y += norm.y; pn->z += norm.z; } mesh->numFaces++; facecount++; } } normalizeNorms(lemMesh.norms, lemMesh.numPoints); if (twistFact >= 1.0f) twistFactAdd = -0.01f; else if (twistFact <= -1.0f) twistFactAdd = 0.01f; twistFact += twistFactAdd; } void initLemScene() { int i; RGBA lightAmbient = {0.0f, 0.0f, 0.0f, 1.0f}; iPrec = (int)(fTesselFact * 32.5); if (iPrec < 5) iPrec = 5; lemX = SaverAlloc(sizeof(double) * iPrec); lemY = SaverAlloc(sizeof(double) * iPrec); lemXT = SaverAlloc(sizeof(double) * iPrec); lemYT = SaverAlloc(sizeof(double) * iPrec); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.5, 1.5, -1.5, 1.5, 0.0, 3.0); glTranslatef(0.0f, 0.0f, -1.5f); newMesh(&lemMesh, (ROT_PREC - 1) * (iPrec - 1) , (ROT_PREC - 1) * (iPrec - 1)); for (i = 0; i < ROT_PREC; i++) { basis[i].x = 0.0f; basis[i].y = (float) (0.15 * cos((i * 2.0 * PI) / (ROT_PREC - 1.0))); basis[i].z = (float) (0.15 * sin((i * 2.0 * PI) / (ROT_PREC - 1.0))); } initLemCoords(iPrec); glFrontFace(GL_CW); glEnable(GL_CULL_FACE); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (GLfloat *) &lightAmbient); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, (GLfloat *) &Material[3].kd); } void delLemScene() { delMesh(&lemMesh); SaverFree(lemX); SaverFree(lemY); SaverFree(lemXT); SaverFree(lemYT); } void updateLemScene(HWND hwnd, int flags) { static double mxrot = 0.0; static double myrot = 0.0; static double mzrot = 0.0; static double mxrotInc = 0.0; static double myrotInc = 0.1; static double zrotInc = 0.1; static double mzrotInc = 0.0; static int h = 0; float r, g, b; RGBA color; MATRIX model; BOOL bounce; zrot += zrotInc; if (zrot >= PI / 4.0) { zrot = PI / 4.0; zrotInc = -0.03; } else if (zrot <= -PI / 4.0) { zrot = -PI / 4.0; zrotInc = 0.03; } genLemniscate(); if (bColorCycle) { HsvToRgb((float)h, 1.0f, 1.0f, &r, &g, &b); color.r = r; color.g = g; color.b = b; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, (GLfloat *) &color); h++; h %= 360; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.5, 1.5, -1.5, 1.5, 0.0, 3.0); glTranslatef(0.0f, 0.0f, -1.5f); glRotatef((GLfloat) (zrot * (180.0 / PI)), 0.0f, 1.0f, 0.0f); glRotatef(50.0f, 1.0f, 0.0f, 0.0f); glRotatef(50.0f, 0.0f, 0.0f, 1.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, -0.5f, 0.0f); glRotatef((GLfloat) (mxrot * (180.0 / PI)), 1.0f, 0.0f, 0.0f); glRotatef((GLfloat) (myrot * (180.0 / PI)), 0.0f, 1.0f, 0.0f); glRotatef((GLfloat) (mzrot * (180.0 / PI)), 0.0f, 0.0f, 1.0f); matrixIdent(&model); matrixRotate(&model, mxrot, myrot, mzrot); matrixTranslate(&model, 0.0, -0.5, 0.0); updateObject(&lemMesh, bSmoothShading); bounce = vShowBuffer(hwnd); mxrot += mxrotInc; myrot += myrotInc; mzrot += mzrotInc; if (bounce) { if (mxrotInc) { mxrotInc = 0.0; myrotInc = 0.1; } else if (myrotInc) { myrotInc = 0.0; mzrotInc = 0.1; } else if (mzrotInc) { mzrotInc = 0.0; mxrotInc = 0.1; } } }