Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

506 lines
16 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: gentex.c
  3. *
  4. * The Textured Flag style of the 3D Flying Objects screen saver.
  5. *
  6. * Texture maps .BMP files onto a simulation of a flag waving in the breeze.
  7. *
  8. * Copyright (c) 1994 Microsoft Corporation
  9. *
  10. \**************************************************************************/
  11. #include <stdlib.h>
  12. #include <windows.h>
  13. #include <GL\gl.h>
  14. #include <GL\glu.h>
  15. #include <string.h>
  16. #include <math.h>
  17. #include "ss3dfo.h"
  18. static float winTotalwidth = (float)0.75;
  19. static float winTotalheight = (float)0.75 * (float)0.75;
  20. #define MAX_FRAMES 20
  21. // IPREC is the number of faces in the mesh that models the flag.
  22. #define IPREC 15
  23. static int Frames = 10;
  24. static MESH winMesh[MAX_FRAMES];
  25. static float sinAngle = (float)0.0;
  26. static float xTrans = (float)0.0;
  27. static int curMatl = 0;
  28. // Material properties.
  29. static RGBA matlBrightSpecular = {1.0f, 1.0f, 1.0f, 1.0f};
  30. static RGBA matlDimSpecular = {0.5f, 0.5f, 0.5f, 1.0f};
  31. static RGBA matlNoSpecular = {0.0f, 0.0f, 0.0f, 0.0f};
  32. // Lighting properties.
  33. static GLfloat light0Pos[] = {20.0f, 5.0f, 20.0f, 0.0f};
  34. static GLfloat light1Pos[] = {-20.0f, 5.0f, 0.0f, 0.0f};
  35. static RGBA light1Ambient = {0.0f, 0.0f, 0.0f, 0.0f};
  36. static RGBA light1Diffuse = {0.4f, 0.4f, 0.4f, 1.0f};
  37. static RGBA light1Specular = {0.0f, 0.0f, 0.0f, 0.0f};
  38. static RGBA flagColors[] = {{1.0f, 1.0f, 1.0f, 1.0f},
  39. {0.94f, 0.37f, 0.13f, 1.0f}, // red
  40. };
  41. // Default texture resource
  42. static TEX_RES gTexRes = { TEX_BMP, IDB_DEFTEX };
  43. static TEXTURE gTex = {0}; // One global texture
  44. /******************************Public*Routine******************************\
  45. * iPtInList
  46. *
  47. * Add a vertex and its normal to the mesh. If the vertex already exists,
  48. * add in the normal to the existing normal (we to accumulate the average
  49. * normal at each vertex). Normalization of the normals is the
  50. * responsibility of the caller.
  51. *
  52. \**************************************************************************/
  53. static int iPtInList(MESH *mesh, int start,
  54. POINT3D *p, POINT3D *norm, BOOL blend)
  55. {
  56. int i;
  57. POINT3D *pts = mesh->pts + start;
  58. if (blend) {
  59. for (i = start; i < mesh->numPoints; i++, pts++) {
  60. if ((pts->x == p->x) && (pts->y == p->y) && (pts->z == p->z)) {
  61. mesh->norms[i].x += norm->x;
  62. mesh->norms[i].y += norm->y;
  63. mesh->norms[i].z += norm->z;
  64. return i;
  65. }
  66. }
  67. } else {
  68. i = mesh->numPoints;
  69. }
  70. mesh->pts[i] = *p;
  71. mesh->norms[i] = *norm;
  72. mesh->numPoints++;
  73. return i;
  74. }
  75. /******************************Public*Routine******************************\
  76. * getZpos
  77. *
  78. * Get the z-position (depth) of the "wavy" flag component at the given x.
  79. *
  80. * The function used to model the wave is:
  81. *
  82. * 1/2
  83. * z = x * sin((2*PI*x + sinAngle) / 4)
  84. *
  85. * The shape of the wave varies from frame to frame by changing the
  86. * phase, sinAngle.
  87. *
  88. \**************************************************************************/
  89. float getZpos(float x)
  90. {
  91. float xAbs = x - xTrans;
  92. float angle = sinAngle + ((float) (2.0 * PI) * (xAbs / winTotalwidth));
  93. xAbs = winTotalwidth - xAbs;
  94. // xAbs += (winTotalwidth / 2.0);
  95. return (float)((sin((double)angle) / 4.0) *
  96. sqrt((double)(xAbs / winTotalwidth )));
  97. }
  98. /******************************Public*Routine******************************\
  99. * genTex
  100. *
  101. * Generate a mesh representing a frame of the flag. The phase, sinAngle,
  102. * is a global variable.
  103. *
  104. \**************************************************************************/
  105. void genTex(MESH *winMesh)
  106. {
  107. POINT3D pos;
  108. POINT3D pts[4];
  109. float w, h;
  110. int i;
  111. newMesh(winMesh, IPREC * IPREC, IPREC * IPREC);
  112. // Width and height of each face
  113. w = (winTotalwidth) / (float)(IPREC + 1);
  114. h = winTotalheight;
  115. // Generate the mesh data. At equally spaced intervals along the x-axis,
  116. // we compute the z-position of the flag surface.
  117. pos.y = (float) 0.0;
  118. pos.z = (float) 0.0;
  119. for (i = 0, pos.x = xTrans; i < IPREC; i++, pos.x += w) {
  120. int faceCount = winMesh->numFaces;
  121. pts[0].x = (float)pos.x;
  122. pts[0].y = (float)(pos.y);
  123. pts[0].z = getZpos(pos.x);
  124. pts[1].x = (float)pos.x;
  125. pts[1].y = (float)(pos.y + h);
  126. pts[1].z = getZpos(pos.x);
  127. pts[2].x = (float)(pos.x + w);
  128. pts[2].y = (float)(pos.y);
  129. pts[2].z = getZpos(pos.x + w);
  130. pts[3].x = (float)(pos.x + w);
  131. pts[3].y = (float)(pos.y + h);
  132. pts[3].z = getZpos(pos.x + w);
  133. // Compute the face normal.
  134. ss_calcNorm(&winMesh->faces[faceCount].norm, pts + 2, pts + 1, pts);
  135. // Add the face to the mesh.
  136. winMesh->faces[faceCount].material = 0;
  137. winMesh->faces[faceCount].p[0] = iPtInList(winMesh, 0, pts,
  138. &winMesh->faces[faceCount].norm, TRUE);
  139. winMesh->faces[faceCount].p[1] = iPtInList(winMesh, 0, pts + 1,
  140. &winMesh->faces[faceCount].norm, TRUE);
  141. winMesh->faces[faceCount].p[2] = iPtInList(winMesh, 0, pts + 2,
  142. &winMesh->faces[faceCount].norm, TRUE);
  143. winMesh->faces[faceCount].p[3] = iPtInList(winMesh, 0, pts + 3,
  144. &winMesh->faces[faceCount].norm, TRUE);
  145. winMesh->numFaces++;
  146. }
  147. // Normalize the vertex normals in the mesh.
  148. ss_normalizeNorms(winMesh->norms, winMesh->numPoints);
  149. }
  150. /******************************Public*Routine******************************\
  151. * initTexScene
  152. *
  153. * Initialize the screen saver.
  154. *
  155. * This function is exported to the main module in ss3dfo.c.
  156. *
  157. \**************************************************************************/
  158. void initTexScene()
  159. {
  160. int i;
  161. float angleDelta;
  162. float aspectRatio;
  163. // Initialize the transform.
  164. glMatrixMode(GL_PROJECTION);
  165. glLoadIdentity();
  166. glOrtho(-0.25, 1.0, -0.25, 1.0, 0.0, 3.0);
  167. glTranslatef(0.0f, 0.0f, -1.5f);
  168. // Initialize and turn on lighting.
  169. glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
  170. glLightfv(GL_LIGHT1, GL_AMBIENT, (GLfloat *) &light1Ambient);
  171. glLightfv(GL_LIGHT1, GL_DIFFUSE, (GLfloat *) &light1Diffuse);
  172. glLightfv(GL_LIGHT1, GL_SPECULAR, (GLfloat *) &light1Specular);
  173. glLightfv(GL_LIGHT1, GL_POSITION, light1Pos);
  174. glEnable(GL_LIGHT1);
  175. glDisable(GL_DEPTH_TEST);
  176. // Leave OpenGL in a state ready to accept the model view transform (we
  177. // are going to have the flag vary its orientation from frame to frame).
  178. glMatrixMode(GL_MODELVIEW);
  179. // Define orientation of polygon faces.
  180. glFrontFace(GL_CW);
  181. // glEnable(GL_CULL_FACE);
  182. Frames = (int)((float)(MAX_FRAMES / 2) * fTesselFact);
  183. // Load user texture - if that fails load default texture resource
  184. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  185. if( ss_LoadTextureFile( &gTexFile, &gTex ) ||
  186. ss_LoadTextureResource( &gTexRes, &gTex) )
  187. {
  188. glEnable(GL_TEXTURE_2D);
  189. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  190. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  191. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  192. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  193. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  194. ss_SetTexture( &gTex );
  195. // Correct aspect ratio of flag to match image.
  196. //
  197. // The 1.4 is a correction factor to account for the length of the
  198. // curve that models the surface ripple of the waving flag. This
  199. // factor is the length of the curve at zero phase. It would be
  200. // more accurate to determine the length of the curve at each phase,
  201. // but this is a sufficient approximation for our purposes.
  202. aspectRatio = ((float) gTex.height / (float) gTex.width)
  203. * (float) 1.4;
  204. if (aspectRatio < (float) 1.0) {
  205. winTotalwidth = (float)0.75;
  206. winTotalheight = winTotalwidth * aspectRatio;
  207. } else {
  208. winTotalheight = (float) 0.75;
  209. winTotalwidth = winTotalheight / aspectRatio;
  210. };
  211. }
  212. if (Frames < 5)
  213. Frames = 5;
  214. if (Frames > MAX_FRAMES)
  215. Frames = MAX_FRAMES;
  216. // Generate the geometry data (stored in the array of mesh structures),
  217. // for each frame of the animation. The shape of the flag is varied by
  218. // changing the global variable sinAngle.
  219. angleDelta = (float)(2.0 * PI) / (float)Frames;
  220. sinAngle = (float) 0.0;
  221. for (i = 0; i < Frames; i++) {
  222. genTex(&winMesh[i]);
  223. sinAngle += angleDelta;
  224. }
  225. }
  226. /******************************Public*Routine******************************\
  227. * delTexScene
  228. *
  229. * Cleanup the data associated with this screen saver.
  230. *
  231. * This function is exported to the main module in ss3dfo.c.
  232. *
  233. \**************************************************************************/
  234. void delTexScene()
  235. {
  236. int i;
  237. for (i = 0; i < Frames; i++)
  238. delMesh(&winMesh[i]);
  239. // Delete the texture
  240. ss_DeleteTexture( &gTex );
  241. }
  242. /******************************Public*Routine******************************\
  243. * updateTexScene
  244. *
  245. * Generate a scene by taking one of the meshes and rendering it with
  246. * OpenGL.
  247. *
  248. * This function is exported to the main module in ss3dfo.c.
  249. *
  250. \**************************************************************************/
  251. void updateTexScene(int flags)
  252. {
  253. MESH *mesh;
  254. MFACE *faces;
  255. int i;
  256. static double mxrot = 23.0;
  257. static double myrot = 23.0;
  258. static double mzrot = 5.7;
  259. static double mxrotInc = 0.0;
  260. static double myrotInc = 3.0;
  261. static double mzrotInc = 0.0;
  262. static int h = 0;
  263. static int frameNum = 0;
  264. POINT3D *pp;
  265. POINT3D *pn;
  266. int lastC, lastD;
  267. int aOffs, bOffs, cOffs, dOffs;
  268. int a, b;
  269. GLfloat s = (GLfloat) 0.0;
  270. GLfloat ds;
  271. // In addition to having the flag wave (an effect acheived by switching
  272. // meshes from frame to frame), the flag changes its orientation from
  273. // frame to frame. This is done by applying a model view transform.
  274. glLoadIdentity();
  275. glRotatef((float)mxrot, 1.0f, 0.0f, 0.0f);
  276. glRotatef((float)myrot, 0.0f, 1.0f, 0.0f);
  277. glRotatef((float)mzrot, 0.0f, 0.0f, 1.0f);
  278. // Divide the texture into IPREC slices. ds is the texture coordinate
  279. // delta we apply as we move along the x-axis.
  280. ds = (GLfloat)1.0 / (GLfloat)IPREC;
  281. // Setup the material property of the flag. The material property, light
  282. // properties, and polygon orientation will interact with the texture.
  283. curMatl = 0;
  284. // glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, &flagColors[0]);
  285. // glMaterialfv(GL_FRONT, GL_SPECULAR, &matlBrightSpecular);
  286. // glMaterialf(GL_FRONT, GL_SHININESS, 60.0);
  287. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, (GLfloat *) &flagColors[0]);
  288. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat *) &matlBrightSpecular);
  289. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, (float) 60.0);
  290. // Pick the mesh for the current frame.
  291. mesh = &winMesh[frameNum];
  292. // Take the geometry data is the mesh and convert it to a single OpenGL
  293. // quad strip. If smooth shading is required, use the vertex normals stored
  294. // in the mesh. Otherwise, use the face normals.
  295. //
  296. // As we define each vertex, we also define a corresponding vertex and
  297. // texture coordinate.
  298. glBegin(GL_QUAD_STRIP);
  299. pp = mesh->pts;
  300. pn = mesh->norms;
  301. for (i = 0, faces = mesh->faces, lastC = faces->p[0], lastD = faces->p[1];
  302. i < mesh->numFaces; i++, faces++) {
  303. a = faces->p[0];
  304. b = faces->p[1];
  305. if (!bSmoothShading) {
  306. // Since flag is a single quad strip, this isn't needed.
  307. // But lets keep it in case we ever change to a more
  308. // complex model (ie., one that uses more than one quad
  309. // strip).
  310. #if 0
  311. if ((a != lastC) || (b != lastD)) {
  312. glNormal3fv((GLfloat *)&(faces - 1)->norm);
  313. glTexCoord2f(s, (float) 0.0);
  314. glVertex3fv((GLfloat *)((char *)pp +
  315. (lastC << 3) + (lastC << 2)));
  316. glTexCoord2f(s, (float) 1.0);
  317. glVertex3fv((GLfloat *)((char *)pp +
  318. (lastD << 3) + (lastD << 2)));
  319. s += ds;
  320. glEnd();
  321. glBegin(GL_QUAD_STRIP);
  322. }
  323. #endif
  324. if (faces->material != curMatl) {
  325. curMatl = faces->material;
  326. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
  327. (GLfloat *) &matlNoSpecular);
  328. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
  329. (GLfloat *) &flagColors[curMatl]);
  330. }
  331. glNormal3fv((GLfloat *)&faces->norm);
  332. glTexCoord2f(s, (float) 0.0);
  333. glVertex3fv((GLfloat *)((char *)pp + (a << 3) + (a << 2)));
  334. glTexCoord2f(s, (float) 1.0);
  335. glVertex3fv((GLfloat *)((char *)pp + (b << 3) + (b << 2)));
  336. s += ds;
  337. } else {
  338. // Since flag is a single quad strip, this isn't needed.
  339. // But lets keep it in case we ever change to a more
  340. // complex model (ie., one that uses more than one quad
  341. // strip).
  342. #if 0
  343. if ((a != lastC) || (b != lastD)) {
  344. cOffs = (lastC << 3) + (lastC << 2);
  345. dOffs = (lastD << 3) + (lastD << 2);
  346. glTexCoord2f(s, (float) 0.0);
  347. glNormal3fv((GLfloat *)((char *)pn + cOffs));
  348. glVertex3fv((GLfloat *)((char *)pp + cOffs));
  349. glTexCoord2f(s, (float) 1.0);
  350. glNormal3fv((GLfloat *)((char *)pn + dOffs));
  351. glVertex3fv((GLfloat *)((char *)pp + dOffs));
  352. s += ds;
  353. glEnd();
  354. glBegin(GL_QUAD_STRIP);
  355. }
  356. #endif
  357. aOffs = (a << 3) + (a << 2);
  358. bOffs = (b << 3) + (b << 2);
  359. if (faces->material != curMatl) {
  360. curMatl = faces->material;
  361. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
  362. (GLfloat *) &matlNoSpecular);
  363. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
  364. (GLfloat *) &flagColors[curMatl]);
  365. }
  366. glTexCoord2f(s, (float) 0.0);
  367. glNormal3fv((GLfloat *)((char *)pn + aOffs));
  368. glVertex3fv((GLfloat *)((char *)pp + aOffs));
  369. glTexCoord2f(s, (float) 1.0);
  370. glNormal3fv((GLfloat *)((char *)pn + bOffs));
  371. glVertex3fv((GLfloat *)((char *)pp + bOffs));
  372. s += ds;
  373. }
  374. lastC = faces->p[2];
  375. lastD = faces->p[3];
  376. }
  377. if (!bSmoothShading) {
  378. glNormal3fv((GLfloat *)&(faces - 1)->norm);
  379. glTexCoord2f(s, (float) 0.0);
  380. glVertex3fv((GLfloat *)((char *)pp + (lastC << 3) + (lastC << 2)));
  381. glTexCoord2f(s, (float) 1.0);
  382. glVertex3fv((GLfloat *)((char *)pp + (lastD << 3) + (lastD << 2)));
  383. } else {
  384. cOffs = (lastC << 3) + (lastC << 2);
  385. dOffs = (lastD << 3) + (lastD << 2);
  386. glTexCoord2f(s, (float) 0.0);
  387. glNormal3fv((GLfloat *)((char *)pn + cOffs));
  388. glVertex3fv((GLfloat *)((char *)pp + cOffs));
  389. glTexCoord2f(s, (float) 1.0);
  390. glNormal3fv((GLfloat *)((char *)pn + dOffs));
  391. glVertex3fv((GLfloat *)((char *)pp + dOffs));
  392. }
  393. glEnd();
  394. // Transfer the image to the floating OpenGL window.
  395. // Determine the flag orientation for the next frame.
  396. // What we are doing is an oscillating rotation about the y-axis
  397. // (mxrotInc and mzrotInc are currently 0).
  398. mxrot += mxrotInc;
  399. myrot += myrotInc;
  400. mzrot += mzrotInc;
  401. if ((myrot < -65.0) || (myrot > 25.0))
  402. myrotInc = -myrotInc;
  403. frameNum++;
  404. if (frameNum >= Frames)
  405. frameNum = 0;
  406. }