1:////////////////////////////////////////////////////////////////////////////// 2:// 3:// CMOTHERBOARD.CPP 4:// Implementation file for CMotherboard, CWhisp classes 5:// 6:// - CMotherboard defines a 3D fly-through of a motherboard 7:// - CWhip is a whisp of light used in the motherboard scene 8:// - Tabs set at 3. (Tronster prefers real tabs, Moby Disk prefers spaces.) 9:// 10:////////////////////////////////////////////////////////////////////////////// 11: 12:#pragma warning(disable:4786) 13:#include <stdlib.h> // Header has rand() 14:#include "CMotherboard.h" 15:#include "loaders3d.h" // GeoGL: 3SO file loader 16:#include "tesselate3d.h" // GeoGL: Object tesselator 17: 18:// Define in CMotherboard header for manual control 19:#ifdef MANUAL_CONTROL 20:#include <iostream> // Manual control supports console output 21:#endif MANUAL_CONTROL 22: 23:// Import geoGL and STL namespaces 24:using namespace geoGL; 25:using namespace std; 26: 27:// User interface control settings 28:#define MOTIONSPEED 0.5f // Speed of manual control 29: 30:// Nifty variations on appearance 31:#define FLUXINESS 0.75f // How much the glowing dots waver around 32:#define WHISP_SIZE (5.0f/3.0f) // Size of whispy lights 33:#define SOCKET_XSIZE 15.0f // Size of CPU socket 34:#define SOCKET_YSIZE 15.0f 35:#define LIGHT_HOVER_Z 10 // Height of lighting light ball above -->motherboard 36: 37:// RGB colors defining "background" of mindware microchip logo 38:#define BACK_GRAY 128 39:#define BACK_RED 128 40:#define BACK_GREEN 128 41:#define BACK_BLUE 128 42: 43:// Light map settings 44:#define LIGHT_FWD_DIST 25 45:#define LIGHT_PWR2 6 46:#define LIGHT_DIM (1<<LIGHT_PWR2) 47:#define LIGHT_SIZE 10.0f 48:#define PHONG 64 49: 50:// Times in MS for start and duration of events 51:#define GLOWSTART 65000 // Glowing starts 52:#define GLOWTIME 4000 53:#define CHIPSTART (GLOWSTART+5000) // Chip starts falling 54:#define CHIPTIME 5000 55:#define ANIMSTART (CHIPSTART+CHIPTIME+GLOWTIME) // Chip logo animates 56:#define ANIMTIME 5000 57:#define FADESTART (ANIMSTART+5000) // Fadeout 58:#define FADETIME 3000 59:#define FINALSTART (FADESTART+FADETIME+3000) 60:#define FINALTIME 1500 61: 62:/******************************** Non-members *********************************/ 63: 64:// Random floating point number 0..1 65:static inline float frand01() { return rand() / static_cast<float>(RAND_MAX); } 66:// Random floating point number -1..1 67:static inline float frand11() { return (rand()/ static_cast<float>(RAND_MAX)) * 2 - 1; } 68: 69:// Generic min/max routines 70:template <class T> static inline T TMAX(T T1, T T2) { return (T1>T2 ? T1 : T2); } 71:template <class T> static inline T TMIN(T T1, T T2) { return (T1<T2 ? T1 : T2); } 72: 73:////////////////////////////////////////////////////////////////////////////// 74:// 75:// Compute animation factor 0..1 76:// - Uses the current & start times and durations to compute a number 0..1 77:// 78:// 79:// RETURNS: 0 = start of effect or before effect 80:// 0-1 = lienar progression between start/end time 81:// 1 = end of effect or after effect 82:// 83:////////////////////////////////////////////////////////////////////////////// 84:static float calcFactor(unsigned int nElapsedTime, unsigned int nStartTime, unsigned int -->nDuration) 85:{ 86: if (nElapsedTime<nStartTime) return 0; 87: if (nElapsedTime>nStartTime+nDuration) return 1; 88: return static_cast<float>(nElapsedTime-nStartTime) / nDuration; 89:} 90: 91:////////////////////////////////////////////////////////////////////////////// 92:// 93:// Load a bitmap texture 94:// - Load image using mediaduke (PNG/BMP/whatever) 95:// - Create mipmapped texture 96:// - Add to geoGL texture list (so object loader can access them) 97:// 98:// ARGS: mediaDuke, Mediaduke object for image loading 99:// filename, name+ext of image file to load 100:// textureName, unique string name of texture for use by object loader 101:// 102:// RETURNS: texture ID number 103:// 104:////////////////////////////////////////////////////////////////////////////// 105:GLuint CMotherboard::loadGLTexture( 106: md::CmediaDuke &mediaDuke, char *filename, char *textureName/*=NULL*/) 107:{ 108: GLuint nTexture; // Texture ID number 109: md::Cimage textureImage; // Mediaduke image 110: 111: // Load image, return on failure 112: if (!mediaDuke.read(filename,textureImage)) 113: { 114: char temp[200]; 115: sprintf(temp,"Unable to read \"%s\"",filename); 116: throw temp; 117: } 118: throwMessage("Unable to read \"%s\"",filename); 119: 120: // Cimage create an opengl texture - returns -1 on error 121: nTexture = textureImage.makeGLTexture(m_oEnvInfo.glWantMipmap, m_oEnvInfo.glWantLinear); 122: 123: // Unable to create texture? Throw an error 124: if (nTexture<=0) { 125: char temp[200]; 126: sprintf(temp,"Unable to create texture \"%s\"",filename); 127: throw temp; 128: } 129: if (nTexture<=0) 130: throwMessage("Unable to create textures \"%s\"",filename); 131: 132: // Add texture to map using unique name. GeoGL object loader can now use this texture. 133: if (textureName) 134: mapTextures[string(textureName)] = nTexture; 135: 136: // Return texture id 137: return nTexture; 138:} 139: 140:/******************************** CDemoEffect *********************************/ 141: 142: 143:////////////////////////////////////////////////////////////////////////////// 144:// 145:// Construct motherboard effect 146:// - Store a reference to the environment information 147:// 148:////////////////////////////////////////////////////////////////////////////// 149:CMotherboard::CMotherboard(CEnvInfo *oEnvInfo) : m_oEnvInfo(*oEnvInfo) {} 150: 151: 152:////////////////////////////////////////////////////////////////////////////// 153:// 154:// Destroy the motherboard 155:// - Has Tronster's cool destructor tracking (for memory leaks) 156:// 157:////////////////////////////////////////////////////////////////////////////// 158:CMotherboard::~CMotherboard() 159:{ 160: MSG("~CMotherboard()") 161: unInit(); 162: MSGEND 163:} 164: 165: 166:////////////////////////////////////////////////////////////////////////////// 167:// 168:// Start the motherboard effect 169:// - Called by demo just before first frame 170:// - Apply opengl settings that other effect may have overridden 171:// - Begin time counter 172:// 173:// RETURNS: true on success (always) 174:// 175:////////////////////////////////////////////////////////////////////////////// 176:bool CMotherboard::start() 177:{ 178: initGLstuff(); // Initialize opengl settings 179: 180: // Setup view frustum 181: glMatrixMode(GL_PROJECTION); 182: glLoadIdentity(); 183: gluPerspective(45.0f,static_cast<float>(m_oEnvInfo.nWinWidth)/m_oEnvInfo.nWinHeight,2,270.0f); --> 184: frustum.init (45.0f,static_cast<float>(m_oEnvInfo.nWinWidth)/m_oEnvInfo.nWinHeight,2,270.0f); --> 185: // force 4/3 aspect ratio even if the window is stretched 186: gluPerspective(45.0f, 4.0f/3.0f, 2,270.0f); 187: frustum.init (45.0f, 4.0f/3.0f, 2,270.0f); 188: glMatrixMode(GL_MODELVIEW); 189: 190: // Save start time, and start the fly through 191: nTimeStart = m_oEnvInfo.getMusicTime(); 192: flight.start(); 193: flight.start(0); 194: 195: // Doesn't bother to check for errors, but it should 196: return true; 197:} 198: 199:////////////////////////////////////////////////////////////////////////////// 200:// 201:// Stop the motherboard effect 202:// - Clear any lighting and weird stuff so other effects are happy 203:// 204:// RETURNS: true on success (always) 205:// 206:////////////////////////////////////////////////////////////////////////////// 207:bool CMotherboard::stop() 208:{ 209: // Disable light attenuation 210: glLightf(GL_LIGHT0+light0.nLightID,GL_LINEAR_ATTENUATION,0); 211: 212: // Turn off all our lights 213: light0.off(); 214: lightSocket.off(); 215: 216: // Doesn't bother to check for errors, but it should 217: return true; 218:} 219: 220:////////////////////////////////////////////////////////////////////////////// 221:// 222:// Initialize and load the motherboard 223:// - Precompute quality values 224:// - Load objects 225:// - Initialize manual control if applicable 226:// 227:// RETURNS: true on success (always) 228:// 229:////////////////////////////////////////////////////////////////////////////// 230:bool CMotherboard::init() 231:{ 232: // Grab demo quality and scale things according to it 233: // It can range 0..10..infinity 234: int nQuality = m_oEnvInfo.nDemoQuality; 235: 236: // Number of whisps to display at each quality setting (0..10) 237: static const float num_Whispy[11] = {32,66,100,134,166,200,280,400,530,660,800}; 238: static const int num_Whispy[11] = {32,66,100,134,166,200,280,400,530,660,800}; 239: if (nQuality<11) 240: nWhispy = num_Whispy[nQuality]; // Normal range (0..10) lookup in table 241: else 242: nWhispy = num_Whispy[10]*nQuality/10; // Above 10, scale lineaarly beyond... 243: nWhispy = num_Whispy[10]*nQuality/10; // Above 10, scale linearly beyond... 244: 245: // How much to tesselate objects 246: // - The BIGGER this is the LESS tesselated 247: // - The SMALLER this is, the MORE tesselated 248: // - This factor will actually refer to the length of the longest side in a 249: // tesselated object. This results in a very nonlinear growth in # of sides! 250: if (nQuality<=2) 251: fTesselationFactor = 1000; // Insanely large, never tesselate 252: else 253: fTesselationFactor = 5.0f/nQuality; // Use quality to determine tesselation 254: 255: // Determine bump map to use 256: // <=5 -- no bump map 257: // 6,7 -- 256x256 bump map 258: // 8+ -- 512x512 bump map 259: if (nQuality>=8) m_szBumpFile = "mb_bump512.png"; else 260: if (nQuality>=6) m_szBumpFile = "mb_bump256.png"; else 261: m_szBumpFile = NULL; 262: 263: 264: // Initialize objects, textures, camera... 265: initObjects(); 266: 267: // Initialize the light map tables for bump map (if doing bump map) 268: if (m_szBumpFile) 269: initLight(); 270: 271: // If under manual control, set the start position 272: #ifdef MANUAL_CONTROL 273: motion = zero3D; 274: rotation= zero3D; 275: #endif 276: 277: // Doesn't bother to check for errors, but it should 278: return true; 279:} 280: 281:////////////////////////////////////////////////////////////////////////////// 282:// 283:// Uninitialize 284:// - Unload objects, textures, etc. Generally free memory. 285:// 286:// RETURNS: true on success (always) 287:// 288:////////////////////////////////////////////////////////////////////////////// 289:// ???WHG??? Add methods to cleanup geometry3d classes 290:bool CMotherboard::unInit() 291:{ 292: // Doesn't bother to check for errors, but it should 293: return true; 294:} 295: 296:////////////////////////////////////////////////////////////////////////////// 297:// 298:// Load all textures 299:// - Load PNG files using mediaduke object (available through CEnvInfo) 300:// - Create procedural textures (for animating mindware logo) 301:// 302:////////////////////////////////////////////////////////////////////////////// 303:void CMotherboard::loadGLTextures() 304:{ 305: // Load generic PNG textures in the "smart" texture IDs 306: text_cap32 = loadGLTexture(m_oEnvInfo.oMedia,"cap32.png", "cap32"); 307: text_res32 = loadGLTexture(m_oEnvInfo.oMedia,"res32.png", "res32"); 308: text_circuit = loadGLTexture(m_oEnvInfo.oMedia,"chip2.png", "circuit"); 309: text_flare1 = loadGLTexture(m_oEnvInfo.oMedia,"flare1.png", "flare1"); 310: text_flare3 = loadGLTexture(m_oEnvInfo.oMedia,"flare3.png", "flare3"); 311: text_mbmap = loadGLTexture(m_oEnvInfo.oMedia,"mb_map.png", "mb_map"); 312: text_socket = loadGLTexture(m_oEnvInfo.oMedia,"socket.png", "socket"); 313: text_slot = loadGLTexture(m_oEnvInfo.oMedia,"slot.png", "slot"); 314: text_metal1 = loadGLTexture(m_oEnvInfo.oMedia,"metal.png", "metal1"); 315: text_microchip1 = loadGLTexture(m_oEnvInfo.oMedia,"microchip1.png", "microchip1"); 316: text_microchip2 = loadGLTexture(m_oEnvInfo.oMedia,"mindwarethreesomecoma2.png","microchip2") -->; 317: text_greenchip = loadGLTexture(m_oEnvInfo.oMedia,"creditschip.png","greenchip"); 318: 319: //////////////// Custom mindware procedural texture //////////////// 320: // This is a texture that starts out blank, but will get drawn on as the effect 321: // progresses. So we load the final image (img_mindware) and hold on to it. Then 322: // another image of matching dimensions is created. This image is made into a texture 323: // that will be used on the actual object. 324: 325: // Load mindware logo 326: if (!m_oEnvInfo.oMedia.read("mindware.png",img_mindware)) 327: { 328: char temp[200]; 329: sprintf(temp,"Unable to read \"%s\"","mindware.png"); 330: throw temp; 331: } 332: throwMessage("Unable to read \"%s\"","mindware.png"); 333: 334: // Convert to RGB 335: // - This would be done automatically if we created a texture out of it 336: if (img_mindware.palette) 337: img_mindware.makeDataRGB(); 338: 339: // Create RGB image to draw on, then fill with neutral color 340: img_mindware0.create(img_mindware.x,img_mindware.y,3); 341: memset(img_mindware0.data, BACK_GRAY, img_mindware0.x*img_mindware0.y*3); 342: 343: // Make image into a texture - throw error if problem arises 344: text_mindware = img_mindware0.makeGLTexture(m_oEnvInfo.glWantLinear, m_oEnvInfo.glWantLinear); --> 345: 346: if (text_mindware<=0) { 347: char temp[200]; 348: sprintf(temp,"Unable to create procedural texture mindware0"); 349: throw temp; 350: } 351: if (text_mindware<=0) 352: throwMessage("Unable to create procedural texture mindware0"); 353: 354: ///////////////////// Custom mindware lightmap ///////////////////// 355: // Load motherboard bump map -- if we are using one 356: if (m_szBumpFile) 357: { 358: if (!m_oEnvInfo.oMedia.read(m_szBumpFile,img_bump)) 359: { 360: char temp[200]; 361: sprintf(temp,"Unable to read \"%s\"",m_szBumpFile); 362: throw temp; 363: } 364: throwMessage("Unable to read \"%s\"",m_szBumpFile); 365: 366: // Verify bump map is 8-bit 367: if (img_bump.bytesPerPixel != 1) 368: throw "Bump map should be 256 color grayscale!"; 369: throwMessage("Bump map should be 256 color grayscale!"); 370: 371: // Create RGB image to draw on, then fill with neutral color 372: img_lightMap.create(img_bump.x,img_bump.y,3); 373: memset(img_lightMap.data, 0, img_lightMap.x*img_lightMap.y*3); 374: 375: // Make image into a texture - throw error if problem arises 376: text_lightMap = img_lightMap.makeGLTexture(m_oEnvInfo.glWantLinear, m_oEnvInfo. -->glWantLinear); 377: 378: if (text_lightMap<=0) { 379: char temp[200]; 380: sprintf(temp,"Unable to create procedural texture text_lightMap"); 381: throw temp; 382: } 383: if (text_lightMap<=0) 384: throwMessage("Unable to create procedural texture text_lightMap"); 385: } else 386: text_lightMap = 0; // Done bump map 387: 388: 389: //////////////// Light beam 1D procedural texture //////////////// 390: // And you thought 1D textures were useless... 391: // Then light beam does not strike on the background color - only on texels 392: // that are going to change. To do this, the light beam uses a 1D texture 393: // as a "mask" for where to draw a line, and where not to draw it 394: 395: // Create a "1D" image 396: // The width is same as the logo, but the height is 1 397: img_animate.create(img_mindware.x,1,3); 398: for (int zz=0; zz<img_animate.x; zz++) { 399: img_animate.data[zz*3+0] = zz; 400: img_animate.data[zz*3+1] = 0; 401: img_animate.data[zz*3+2] = zz; 402: } 403: 404: // Allocate Texture ID using GeoGL "smart" texture object 405: text_animate.create(); 406: 407: // Create a 1D texture 408: // - MediaDuke doesn't have a nice function to do this for me 409: 410: // Bind 1D texture 411: glBindTexture(GL_TEXTURE_2D, 0); 412: glBindTexture(GL_TEXTURE_1D, text_animate); 413: 414: // Use linear interpolation, mipmaps would be silly 415: glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,m_oEnvInfo.glWantLinear); 416: glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,m_oEnvInfo.glWantLinear); 417: 418: // Create the texture 419: glTexImage1D(GL_TEXTURE_1D,0,3,img_animate.x,0, 420: GL_RGB,GL_UNSIGNED_BYTE,img_animate.data); 421: 422: // Release the 1D texture binding 423: glBindTexture(GL_TEXTURE_1D, 0); 424:} 425: 426:////////////////////////////////////////////////////////////////////////////// 427:// 428:// Create circular light 429:// - Computes simple light into img_light image 430:// 431:////////////////////////////////////////////////////////////////////////////// 432:void CMotherboard::initLight() 433:{ 434: // Create a circular light 435: img_light.create(LIGHT_DIM,LIGHT_DIM,1); 436: for (int j=0; j<LIGHT_DIM; j++) 437: { 438: for (int i=0; i<LIGHT_DIM; i++) 439: { 440: float dist = (LIGHT_DIM/2-i)*(LIGHT_DIM/2-i) + (LIGHT_DIM/2-j)*(LIGHT_DIM/2-j); 441: if (fabsf(dist)>1) 442: dist = sqrtf(dist); 443: int c = (int)(LIGHT_SIZE*dist); //???WHG Random deviation + (rand()%7)-3; 444: if (c<0) c = 0; 445: if (c>255) c = 255; 446: img_light.data[(j<<LIGHT_PWR2)+i] = 255-c; 447: } 448: } 449:} 450: 451:////////////////////////////////////////////////////////////////////////////// 452:// 453:// Set light attenuation 454:// - Some sucky opengl drivers don't support this. Maybe we need an option 455:// to disable it. 456:// 457:////////////////////////////////////////////////////////////////////////////// 458:void CMotherboard::setAttenuation() 459:{ 460: // For those not versed in light attenuation: 461: // Attenuation causes light to affect distant objects less than near ones 462: // It can be constant, linear, or quadratic. 463: // Just a slight linear falloff allows a bit of realizm and cloaks 464: // far away details(and artifacts) until nearby 465: 466: // Maybe GeoGL's Light3D class should support this 467: glLightf(GL_LIGHT0+light0.nLightID,GL_LINEAR_ATTENUATION,0.05f); 468:} 469: 470:////////////////////////////////////////////////////////////////////////////// 471:// 472:// Apply opengl settings, fog, attenuation, light... 473:// - Use glEnable to setup things that other demo effects may have changed 474:// - Setup the lights and the ambient light 475:// 476:////////////////////////////////////////////////////////////////////////////// 477:void CMotherboard::initGLstuff() // All Setup For OpenGL Goes Here 478:{ 479:// OpenGL setup 480: glEnable(GL_DEPTH_TEST); // Enables Depth Testing 481: glEnable(GL_CULL_FACE); // Cull back faces 482: glDisable(GL_NORMALIZE); // GeoGL creates unit normals at load 483: glShadeModel(GL_SMOOTH); // Enable Smooth Shading 484: glDepthFunc(GL_LEQUAL); // Allows blends to be drawn over objects 485: glEnable(GL_LIGHTING); // Lighting is key... 486: 487: setAttenuation(); // Set light attenuation 488: 489:// Light setup 490: 491: // Disable any lights left around by other effects 492: for (int i=0; i<1; i++) 493: glDisable(GL_LIGHT0+i); 494: 495: // No scene ambient light - the individual lights handle this 496: Light3D::setSceneAmbient(fRGBA(0,0,0,0)); 497: 498: // Light at viewer is on at full white 499: light0.setLight(1.0f,1.0f,1.0f,1); 500: light0.position(0.0f,0.0f,0.0f); 501: light0.on(); 502: 503: // Light at CPU socket comes later 504: lightSocket.off(); 505:} 506: 507:////////////////////////////////////////////////////////////////////////////// 508:// 509:// Initialize openGL objects 510:// - Load objects with GeoGL object loader 511:// - Customize texture, light, position, transparency 512:// 513:////////////////////////////////////////////////////////////////////////////// 514:void CMotherboard::initObjects() 515:{ 516: // Load fly through path 517: flight.Load("data.md/flythrough.dat"); 518: 519: // Load all textures before objects 520: loadGLTextures(); 521: 522: // ABOUT GEOGL OBJECT LOADING 523: // - Objects are loaded at the origin. The motherboard is on the XY plane, so 524: // other objects are placed above it (+z) at various positions 525: // - Objects may be tesselated so the triangle-mesh is more detailed. This can 526: // aid lighting effects (particularly specular light) but eats memory+T&L time 527: // - When objects are loaded, GeoGL will use the texture and light settings 528: // specified in the 3SO file. Some objects are "generic" (cube, plane) and 529: // need to have the texture, color, etc. set manually. Custom objects load 530: // exactly as needed (resistor, CPU chip) 531: 532: // COMPUTER CASE: load, scale, position 533: // - It is a 2-sided cube (2-sided else inside is culled) 534: // - Metal texture is specified in the 3SO file 535: computer = Load3SO("data.md/cube2s.3so",NULL,false); 536: computer.rescale(80,120,40); 537: computer.compile(); 538: 539: // MOTHERBOARD: load, tesselate, scale, position 540: // - Tesselated since lighting must be computed at more just the 4 corners! 541: // - Uses large, detailed 512x512 texture 542: motherboard = Load3SO("data.md/mb_map.3so",NULL,false); 543: motherboard = splitObj(motherboard,0.5f); 544: motherboard.rescale(70,80,1); 545: motherboard.position(0,-20,-37); 546: motherboard.compile(); 547: 548: // CPU SOCKET: load, scale, position 549: // - Uses simple texture showing holes in socket 550: socket = Load3SO("data.md/socket.3so",NULL,false); 551: socket.rescale(SOCKET_XSIZE,SOCKET_YSIZE,0.8); 552: socket.position = motherboard.position + fVector3D(0,49,0.8); 553: socket.compile(); 554: 555: // SOCKET HANDLE: load, scale, position, orient, 556: // - Reorient with the motherboard 557: socketHandle = Load3SO("data.md/handle.3so",NULL,false); 558: socketHandle.rescale(1,0.5f,36.5f); 559: socketHandle.position = motherboard.position + fVector3D(21.5f,33.5f,0); 560: socketHandle.direction(0,-90,0); 561: socketHandle.compile(); 562: 563: // CPU CHIP: load, scale, position, set texture 564: // - Created from a generic cube so the texture must be set 565: // - Size is slightly smaller than the socket 566: CPUchip = Load3SO("data.md/cube.3so",NULL,false); 567: CPUchip.rescale(SOCKET_XSIZE - 0.2f,SOCKET_YSIZE - 0.2f,0.5); 568: CPUchip.position = socket.position + fVector3D(0,0,100); 569: FOROBJSET(CPUchip,chipobj) 570: chipobj.nTextureID = text_mindware; 571: ENDFOROBJSET 572: CPUchip.compile(); 573: 574: // COOLCHIP: load, tesselate, scale, position 575: // - Tesselated for nice specular highlight 576: // - Created from a generic cube so the texture must be set 577: // - Play with the default lighting too 578: // - This used to be a big green chip, now it shows the credits 579: coolchip = Load3SO("data.md/cube.3so",NULL,false); 580: coolchip = splitObj(coolchip,0.75f*fTesselationFactor); 581: coolchip.rescale(11,10,0.5); 582: coolchip.position = motherboard.position + fVector3D(7,13,0.6); 583: FOROBJSET(coolchip,chipobj) 584: chipobj.nTextureID = text_greenchip; 585: chipobj.color(0.6f,1.0f,0.6f); 586: chipobj.setLight(0.15f,1.0f,0,1.5f,10); 587: chipobj.bSpecularBlend = true; // Apply 2-pass specular blend 588: chipobj.bDrawSmooth = true; 589: ENDFOROBJSET 590: coolchip.compile(); 591: 592: // CAPACITOR TABLE 593: // - This is the coordinates of all the capacitors on the motherboard 594: fVector3D cap_pos[num_Cap] = { 595: fVector3D(-45,50,0), fVector3D(-45,44,0), fVector3D(-45,38,0), 596: fVector3D(-45,32,0), fVector3D(-45,26,0), 597: 598: fVector3D(-39,-6,0), fVector3D(-38.5,-12,0), 599: fVector3D(-35,-32,0), fVector3D(-6,-33,0), 600: fVector3D(-12,-44,0), fVector3D(7,-53,0), 601: fVector3D(30,-44,0), fVector3D(34,-13,0), 602: fVector3D(30,68,0), fVector3D(21,69,0), 603: fVector3D(16,68,0), fVector3D(3,68,0), 604: fVector3D(-1.5,68.5,0), fVector3D(-9,68.2,0) 605: }; 606: 607: // - This is the orientation of all the capacitors on the motherboard 608: fVector3D cap_dir[num_Cap] = { 609: fVector3D(0,270,10), fVector3D(4,320,6), fVector3D(-1,130,0), 610: fVector3D(11,200,7), fVector3D(0,110,0), 611: fVector3D(20,360,5), fVector3D(-19,210,0), 612: fVector3D(0,140,-8), fVector3D(7,90,-13), 613: fVector3D(-5,110,3), fVector3D(12,120,0), 614: fVector3D(15,60,-1), fVector3D(0,70,0), 615: fVector3D(-3,280,0), fVector3D(2,150,-7), 616: fVector3D(13,40,4), fVector3D(0,10,0), 617: fVector3D(-16,80,0), fVector3D(13,256,2) 618: }; 619: 620: // MAIN CAPACITOR: load, tesselate, scale, position, reorient 621: // - Tesselated for specular highlight 622: ObjectSet3D cap_main = Load3SO("data.md/cap.3so",NULL,false); 623: cap_main = splitObj(cap_main,0.75f*fTesselationFactor); 624: cap_main.rescale(2.0f,1.5f,2.0f); 625: cap_main.direction(90,0,0); 626: cap_main.position = motherboard.position + fVector3D(0,0,1.5f*1.5f); 627: cap_main.objects[0].bSpecularBlend = true; 628: 629: // Loop through capacitor table and create a capacitor for each position 630: // - Copies of the original capacitor object (share vertices) 631: // - Position & orientation from the above tables 632: // - Random colors, 50% are specular 633: for (int nCap=0; nCap<num_Cap; nCap++) { 634: capacitor[nCap] = cap_main; // Copy original 635: capacitor[nCap].position +=cap_pos[nCap]; // Add to position, direction 636: capacitor[nCap].direction+=cap_dir[nCap]; 637: 638: // Every other one 639: if (nCap % 2==0) 640: { 641: // Is given a random color change of about 50% 642: Object3D &obj = capacitor[nCap].objects[0]; 643: obj.diffuse.r = obj.diffuse.r*(frand01()/2 + 0.5f); 644: obj.diffuse.g = obj.diffuse.g*(frand01()/2 + 0.5f); 645: obj.diffuse.b = obj.diffuse.b*(frand01()/2 + 0.5f); 646: } 647: // And every other one is specular 648: cap_main.objects[0].bSpecularBlend = (nCap % 2==0); 649: capacitor[nCap].compile(); 650: } 651: 652: // RESISTOR TABLE 653: // - This is the coordinates of all the capacitors on the motherboard 654: fVector3D res_pos[num_Res] = { 655: fVector3D(-55,68,0), fVector3D(-55,65,0), 656: fVector3D(-55,62,0), fVector3D(-55,59,0), 657: }; 658: 659: // - This is the orientation of all the capacitors on the motherboard 660: fVector3D res_dir[num_Res] = { 661: fVector3D(0,0,90), fVector3D(0,0,90), 662: fVector3D(0,0,90), fVector3D(0,0,90), 663: }; 664: 665: // MAIN RESISTOR: load, scale, position 666: // - Tesselated for specular highlight 667: ObjectSet3D res_main = Load3SO("data.md/res.3so",NULL,false); 668: res_main.position = motherboard.position + fVector3D(0,0,1.0f); 669: res_main.compile(); 670: 671: // Loop through resistor table and create a resistor for each position 672: // - Copies of the original resistor object (share vertices) 673: // - Position & orientation from the above tables 674: for (int nRes=0; nRes<num_Res; nRes++) { 675: resistor[nRes] = res_main; 676: resistor[nRes].position +=res_pos[nRes]; 677: resistor[nRes].direction+=res_dir[nRes]; 678: } 679: 680: // MAIN PCI SLOT: load, tesselate, scale, position 681: // - Created from a generic cube so the texture must be set 682: PCI[0] = Load3SO("data.md/slot.3so",NULL,false); 683: PCI[0] = splitObj(PCI[0],1*fTesselationFactor); 684: PCI[0].rescale(28,2,2); 685: PCI[0].position = motherboard.position + fVector3D(-13,-27,1); 686: PCI[0].compile(); 687: 688: // Loop creating PCI slots, next to each other 689: // - Each idential 690: for (int nPCI=1; nPCI<num_PCI; nPCI++) { 691: PCI[nPCI] = PCI[0]; 692: PCI[nPCI].position+=fVector3D(0,-11*nPCI,0); 693: } 694: 695: // AGP SLOT: load, tesselate, scale, position 696: // - Uses PCI slot object, but is a lighter color 697: AGP = Load3SO("data.md/slot.3so",NULL,false); 698: AGP = splitObj(AGP,1*fTesselationFactor); 699: AGP.rescale(24,2,2); 700: AGP.position= PCI[0].position + fVector3D(13,12,0); 701: FOROBJSET(AGP,obj) 702: obj.color(1,0.85f,0.48f); 703: obj.setLight(0.1,0.4,0,0,0); 704: ENDFOROBJSET 705: AGP.compile(); 706: 707: // ISA SLOT : load, tesselate, scale, position 708: // - Uses PCI slot object, but is a darker color 709: ISA = Load3SO("data.md/slot.3so",NULL,false); 710: ISA = splitObj(ISA,1*fTesselationFactor); 711: ISA.rescale(45,2,2); 712: ISA.position= PCI[num_PCI-1].position + fVector3D(7,-6,0); 713: FOROBJSET(ISA,obj) 714: obj.diffuse = PCI[0].objects[0].diffuse / 4; 715: ENDFOROBJSET 716: ISA.compile(); 717: 718: // MAIN DIMM SLOT: load, tesselate, scale, position 719: // - Uses PCI slot object, but is darker, thinner, shorter 720: ObjectSet3D DIMM0 = Load3SO("data.md/slot.3so",NULL,false); 721: DIMM0 = splitObj(DIMM0,1*fTesselationFactor); 722: DIMM0.rescale(17,1,1); 723: DIMM0.direction = fVector3D(0,0,90); 724: DIMM0.position = motherboard.position+fVector3D(47,54,0.5f); 725: FOROBJSET(DIMM0,obj) 726: obj.diffuse = PCI[0].objects[0].diffuse / 4; 727: ENDFOROBJSET 728: DIMM0.compile(); 729: 730: // DIMM SLOTS: create 3 dimm slots (each pair forms one memory slot) 731: DIMM[0] = DIMM0; DIMM[0].position += fVector3D( 0, 0,0); 732: DIMM[1] = DIMM0; DIMM[1].position += fVector3D( 0,-34,0); 733: DIMM[2] = DIMM0; DIMM[2].position += fVector3D(-3, 0,0); 734: DIMM[3] = DIMM0; DIMM[3].position += fVector3D(-3,-34,0); 735: DIMM[4] = DIMM0; DIMM[4].position += fVector3D(-6, 0,0); 736: DIMM[5] = DIMM0; DIMM[5].position += fVector3D(-6,-34,0); 737: 738: // RAM CHIP: load, tesselate, scale, position 739: // - Created from a generic cube so the texture must be set 740: RAM = Load3SO("data.md/cube.3so",NULL,false); 741: RAM.rescale(0.4f,33,7); 742: RAM.position = motherboard.position+fVector3D(47,37,3.5f); 743: FOROBJSET(RAM,obj) 744: obj.nTextureID = text_circuit; 745: ENDFOROBJSET 746: RAM.compile(); 747: 748: // SOME MICROCHIPS: load, scale, position, orientation 749: // - Created from a generic cube so the texture must be set 750: microchip[0] = Load3SO("data.md/chip.3so",NULL,false); 751: microchip[0].rescale(11,1,5); 752: microchip[0].direction = fVector3D(90,90,180); 753: microchip[0].position = motherboard.position + fVector3D(-47,-62,1); 754: microchip[0].compile(); 755: 756: microchip[1] = Load3SO("data.md/chip.3so",NULL,false); 757: microchip[1].objects[0].nTextureID = text_microchip2; 758: microchip[1].rescale(6,1,3.5f); 759: microchip[1].position = motherboard.position + fVector3D(-48,-44,1); 760: microchip[1].direction = fVector3D(90,0,180); 761: microchip[1].compile(); 762: 763: microchip[2] = Load3SO("data.md/chip.3so",NULL,false); 764: microchip[2].rescale(5,0.75f,2.5f); 765: microchip[2].position = motherboard.position + fVector3D(30,-5,0.75f); 766: microchip[2].direction = fVector3D(90,0,180); 767: microchip[2].compile(); 768: 769: // LIGHT BEAM: load, scale, position, orientation 770: // - This is the light beam that "etches" onto the mindware chip 771: // - Created from a generic plane so many things are changed 772: lightBeam = Load3SO("data.md/plane.3so",NULL,false); 773: lightBeam.rescale(20,20,20); 774: lightBeam.direction(90,-45,0); 775: lightBeam.position = socket.position + fVector3D(-15,-15,20); 776: FOROBJSET(lightBeam,obj) 777: obj.color = fwhite; 778: obj.bTransparency = true; // Oooh, transparency! 779: obj.nTextureType = GL_TEXTURE_1D; // And a 1D texture! 780: obj.nTextureID = text_animate; // A procedural one! 781: obj.ambient(0,0,0,1); // These settings make 50% transparency 782: obj.diffuse(0,0,0,0.5f); // They are magic, so don't muck with them 783: obj.specular(0,0,0,1); 784: obj.emission(1,1,1,1); 785: ENDFOROBJSET 786: 787: // EXPLODING LIGHT FLARE: load, scale, position 788: // - This object explodes out from the socket when the glowing starts 789: // - Created from a generic plane and heavily modified 790: flare = Load3SO("data.md/plane.3so",NULL,false); 791: flare.position = motherboard.position + fVector3D(0,49,0.8); 792: FOROBJSET(flare,flareobj) 793: flareobj.color(1,1,1,1); 794: flareobj.bTransparency = true; 795: flareobj.nTextureID = text_flare3; 796: flareobj.ambient(0,0,0,1); 797: flareobj.diffuse(0,0,0,0); 798: flareobj.specular(0,0,0,1); 799: flareobj.emission(1,1,1,1); 800: ENDFOROBJSET 801: 802: motherboardBump = motherboard; 803: FOROBJSET(motherboardBump,obj) 804: obj.color(1,1,1,1); 805: obj.bTransparency = true; 806: obj.nTextureID = text_lightMap; 807: obj.ambient(0,0,0,1); 808: obj.diffuse(0,0,0,0.5f); 809: obj.specular(0,0,0,1); 810: obj.emission(1,1,1,1); 811: ENDFOROBJSET 812: 813: // GLOWING COLUMN: load, scale, position, orientation 814: // - Created from a generic cube so attributes are changed 815: // - GlowingOld is the original cube object and scale 816: // - Glowing is an object that will change shape and size 817: glowing = Load3SO("data.md/cube.3so",NULL,false); // Load twice instead of copying 818: glowingOld = Load3SO("data.md/cube.3so",NULL,false); // So they don't share vertices 819: glowing.rescale(14.9f,1.0f,14.9f); 820: glowingOld.rescale(14.9f,1.0f,14.9f); 821: glowing.direction(90,0,0); 822: glowing.position = motherboard.position + fVector3D(0,49,1.8); 823: // Transparent, no texture 824: FOROBJSET(glowing,obj) 825: obj.color(1,1,1,1); 826: obj.ambient(0,0,0,0); 827: obj.diffuse(0,0,0,0.0); 828: obj.specular(0,0,0,0); 829: obj.bSpecularBlend = false; 830: obj.emission(1,1,1,1); 831: obj.bTransparency = true; 832: obj.nTextureID = 0; 833: ENDFOROBJSET 834: 835: // MAIN WHISP: load, scale, position, orientation 836: // - Created from a generic plane so attributes are changed 837: ObjectSet3D whispy_main = Load3SO("data.md/plane.3so",NULL,false); 838: whispy_main.position = motherboard.position + fVector3D(0,49,5000); 839: whispy_main.direction(45,0,0); 840: whispy_main.rescale(WHISP_SIZE,WHISP_SIZE,WHISP_SIZE); 841: FOROBJSET(whispy_main,obj) 842: obj.color(1,1,1,1); 843: obj.bTransparency = true; 844: obj.nTextureID = text_flare1; 845: obj.ambient(0,0,0,1); 846: obj.diffuse(0,0,0,0); 847: obj.specular(0,0,0,1); 848: obj.emission(1,1,1,1); 849: ENDFOROBJSET 850: 851: // Create a multitude of whisp objects that are waay to high to be seen 852: // - since they are so high above the chip, they will get reset right away 853: // - Scale the # of whisps according to the quality factor 854: whispy.refnew(nWhispy); 855: whispyData.refnew(nWhispy); 856: for (int nWhisp=0; nWhisp<nWhispy; nWhisp++) 857: { 858: whispy[nWhisp] = whispy_main; // Copy original, share vertices 859: whispyData[nWhisp].basePos.z = 5000; // Position way up high 860: } 861: 862: // All objects are now ready to be rendered 863:} 864: 865:////////////////////////////////////////////////////////////////////////////// 866:// 867:// Call a visible object 868:// - Checks to see if the object is in the view frustum 869:// - Only draws the object if it is 870:// - Call only works on compiled objects 871:// 872:// ARGS: obj, GeoGL "ObjectSet3D" to call 873:// 874:// RETURNS: true if object visible, false if not 875:////////////////////////////////////////////////////////////////////////////// 876:bool CMotherboard::drawVisibleObject(ObjectSet3D &obj) 877:{ 878: if (frustum.visible(obj)) 879: { 880: obj.call(); 881: return true; 882: } else 883: return false; 884:} 885: 886:void CMotherboard::drawBump(int lx1, int ly1) 887:{ 888: int i, j, px, py, x, y, offs, c; 889: int bump_w = img_lightMap.x; 890: int bump_h = img_lightMap.y; 891: 892: offs = bump_w; 893: int lx = -lx1 + LIGHT_DIM/2; // lx1 ranges 0..LIGHT_DIM. Change to -LIGHT_DIM/2 to -->+LIGHT_DIM/2 894: int ly = -ly1 + LIGHT_DIM/2; // ly1 ranges 0..LIGHT_DIM. Change to -LIGHT_DIM/2 to -->+LIGHT_DIM/2 895: for (j=1; j<bump_h; j++) 896: { 897: img_lightMap.data[offs*3 + 0] = 0; 898: img_lightMap.data[offs*3 + 1] = 0; 899: img_lightMap.data[offs*3 + 2] = 0; 900: offs++; 901: for (i=1; i<bump_w; i++) 902: { 903: // Calculate the slope for each pixels 904: px = i + img_bump.data[offs-1] - img_bump.data[offs]; 905: py = j + img_bump.data[offs-bump_w] - img_bump.data[offs]; 906: 907: // Lookup the first light map to have to light intensisy of this point 908: x = px + lx; 909: y = py + ly; 910: if ((y>=0) && (y<LIGHT_DIM) && (x>=0) && (x<LIGHT_DIM)) 911: c = img_light.data[(y<<LIGHT_PWR2)+x]; 912: else 913: c = 0; 914: 915: // Do not underflow or overflow 916: if (c<0) c = 0; 917: if (c>255) c = 255; 918: 919: img_lightMap.data[offs*3 + 0 ] = c; 920: img_lightMap.data[offs*3 + 1 ] = c; 921: img_lightMap.data[offs*3 + 2 ] = c; 922: 923: offs++; 924: } 925: } 926: 927: // Only update changed portions of the light map image 928: // This could be MUCH more optimal 929: int top, bott, subOffset; 930: 931: top = TMAX<int>(ly1 - LIGHT_DIM/2,0); // Top of area affected by light 932: bott= TMIN<int>(ly1 + LIGHT_DIM/2,img_lightMap.y-1); // Bottom of area affected by light 933: subOffset = top*img_lightMap.x*3; // Offset of top 934: 935: // Update the light map - only update the portion that is affected 936: // ???WHG 1) This still updates all the way across 937: // ???WHG 2) This should leave trails since we did not include the area from the previous -->frame! 938: glBindTexture(GL_TEXTURE_2D, text_lightMap); 939: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, top, img_lightMap.x,bott-top+1, 940: GL_RGB, GL_UNSIGNED_BYTE,img_lightMap.data+subOffset); 941: glBindTexture(GL_TEXTURE_2D, 0); 942: 943:} 944: 945:////////////////////////////////////////////////////////////////////////////// 946:// 947:// Advance the light map effect 948:// - This computes a bump map for the motherboard 949:// - It is centered around the light in front of the viewer 950:// 951:////////////////////////////////////////////////////////////////////////////// 952:#define MB_X0 (-70 - 0) 953:#define MB_X1 (+70 - 0) 954:#define MB_Y0 (-80 - 20) 955:#define MB_Y1 (+80 - 20) 956:#define MB_X (MB_X1 - MB_X0) 957:#define MB_Y (MB_Y1 - MB_Y0) 958: 959:void CMotherboard::advanceLightMap() 960:{ 961: // Exit if we are not doing bump mapping 962: if (!m_szBumpFile) 963: return; 964: 965: int lx,ly; 966: fVector2D lightPos; 967: 968: // Compute position of light, projected onto MB, range 0..1 969: lightPos.x = (light0.position.x - MB_X0) / MB_X; 970: lightPos.y = (light0.position.y - MB_Y0) / MB_Y; 971: 972: // Clamp in case it goes off the MB 973: if (lightPos.x<0) lightPos.x = 0; else 974: if (lightPos.x>1) lightPos.x = 1; 975: if (lightPos.y<0) lightPos.y = 0; else 976: if (lightPos.y>1) lightPos.y = 1; 977: 978: // Scale it to the resolution of the light map 979: lx = lightPos.x * img_lightMap.x; 980: ly = lightPos.y * img_lightMap.y; 981: lx = static_cast<int>(lightPos.x * img_lightMap.x); 982: ly = static_cast<int>(lightPos.y * img_lightMap.y); 983: 984: // Bump map not changed, return 985: if (lx==lx0 && ly==ly0) 986: return; 987: lx0 = lx; 988: ly0 = ly; 989: 990: drawBump(lx,ly); 991:} 992: 993:////////////////////////////////////////////////////////////////////////////// 994:// 995:// Advance the animation for the mindware chip 996:// - Computes the procedural texture img_mindware and sends it to opengl 997:// - Computes the procedural 1D texture for the "etching" light beam 998:// 999:// ARGS: fAnimateFactor, 0..1 (0 is starting, 1 is completed) 1000:////////////////////////////////////////////////////////////////////////////// 1001:void CMotherboard::advanceChipTexture(float fAnimateFactor) 1002:{ 1003: static const int nAhead = 50; // # of pixels ahead for white glow 1004: static const int nWhiteness = 5; // Brightness factor for these pixels 1005: 1006: // The image appears on the chip coming from one corner moving to another. 1007: // This is commonly called a "diagonal wipe" 1008: // Just ahead of the wipe, the pixels-to-be glow white, and fade down to the 1009: // proper color. This only happens on non-background pixels. 1010: // 1011: // In addition, a glowing beam carves out the sections that are being drawn. 1012: // The beam fires at the glowing points that are ahead of the wiped pixels. 1013: // - The wipe cannot depend on previous frames (due to frameskip) 1014: // - A 1D texture must be plotted with the section the beam carves 1015: // - The texture must be NxN, RGB8 1016: // - The 1D texture must be Nx1 1017: // - "Diagonals" range 0..2N 1018: // - The diagonal of a pixel at (x,y) in an NxN texture is (x+y) 1019: 1020: md::Cimage &image0 = img_mindware0; // Working image to draw on 1021: md::Cimage &image = img_mindware; // Final image to draw from 1022: 1023: int nCurrDiag = fAnimateFactor * (image.x+image.y); // Current diagonal at full color 1024: int nCurrDiag = static_cast<int>( 1025: fAnimateFactor * (image.x+image.y));// Current diagonal at full color 1026: int nGlowDiag = nCurrDiag + nAhead; // Current glowing diagonal 1027: int nOffset = 0; // Offset of (x,y) pixel in texture 1028: 1029: // Erase the carved 1D texture. This is filled in as we go 1030: memset(img_animate.data,0,img_animate.x*3); 1031: 1032: // Loop through texture 1033: for (int y=0; y<image.y; y++) 1034: { 1035: for (int x=0; x<image.x; x++) 1036: { 1037: int nDiag = x+y; // Current diagonal (0..x+y) 1038: nOffset += 3; // Update offset 1039: 1040: // Is this diagonal on or before the current diagonal? 1041: if (nDiag <= nCurrDiag) 1042: { 1043: // Then set the color to the final color 1044: image0.data[nOffset+0] = image.data[nOffset+0]; 1045: image0.data[nOffset+1] = image.data[nOffset+1]; 1046: image0.data[nOffset+2] = image.data[nOffset+2]; 1047: } else 1048: 1049: // Is this diagonal between the current diagonal and the white glowing diagonal? 1050: if (nDiag <= nCurrDiag + nAhead) 1051: { 1052: // Only glow pixels that are not "background" gray 1053: if (image.data[nOffset+0]!=BACK_RED || 1054: image.data[nOffset+1]!=BACK_GREEN || 1055: image.data[nOffset+2]!=BACK_BLUE) 1056: { 1057: // Glow far ahead pixels white, fade down to proper color 1058: 1059: int nWhite = (nDiag - nCurrDiag) * nWhiteness; // Whiteness factor 1060: 1061: // Add the whiteness to the pixel color 1062: image0.data[nOffset+0] = TMIN(image.data[nOffset+0] + nWhite,255); 1063: image0.data[nOffset+1] = TMIN(image.data[nOffset+1] + nWhite,255); 1064: image0.data[nOffset+2] = TMIN(image.data[nOffset+2] + nWhite,255); 1065: 1066: // Is this the brightest glowing diagonal? 1067: if (nDiag == nCurrDiag + nAhead) 1068: { 1069: // Yes it is - this is where the 1D carving glow strikes 1070: // This pixel is glowing, so we add it to the mask. This is a mess. 1071: 1072: int nLen, nVal; 1073: 1074: // Need: 1) The length of the current diagonal (0..N) 1075: // 2) The coordinate to decide the offset along that diagonal 1076: if (nDiag <= img_animate.x) 1077: { nLen = nDiag; nVal = x; } 1078: else 1079: { nLen = 2*img_animate.x - nDiag; nVal = img_animate.x - y; } 1080: 1081: // Compute the offset (-N/2..N/2) along the diagonal 1082: // Then compute the pixel in the 1D image that it corresponds to 1083: int nOffset = nLen/2 - nVal; 1084: int nPixel = img_animate.x/2 - nOffset; 1085: 1086: // I think it is going out of range by 1 sometimes, due to the rounding 1087: if (nPixel>=0 && nPixel<img_animate.x) 1088: { 1089: // Compute offset, set to white 1090: int z = nPixel * 3; 1091: img_animate.data[z+0] = 255; 1092: img_animate.data[z+1] = 255; 1093: img_animate.data[z+2] = 255; 1094: } 1095: } // end 1D texture at brightest diagonal 1096: } // end any pixel that is not the background color 1097: } // end which diagonal 1098: 1099: // Update offset 1100: nOffset += 3; 1101: 1102: } // end X 1103: } // end Y 1104: 1105: // Wow, now lets move the plane onto the appropriate diagonal 1106: // We compute the position of the texture's diagonal in 3D space 1107: float fGlowDiagonal = (float)(nCurrDiag+nAhead)/(image.x+image.y); 1108: lightBeam.position = 1109: socket.position + 1110: fVector3D(-SOCKET_XSIZE+SOCKET_XSIZE*2*fGlowDiagonal, 1111: -SOCKET_YSIZE+SOCKET_YSIZE*2*fGlowDiagonal, 20); 1112: 1113: // Update the chip drawing 1114: // Use glTexSubImage2D to update a texture 1115: glBindTexture(GL_TEXTURE_2D, text_mindware); 1116: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, img_mindware0.x,img_mindware0.y, 1117: GL_RGB, GL_UNSIGNED_BYTE,img_mindware0.data); 1118: glBindTexture(GL_TEXTURE_2D, 0); 1119: 1120: // Update the light beam 1121: // Use glTexSubImage1D to update a texture 1122: glBindTexture(GL_TEXTURE_1D, text_animate); 1123: glTexSubImage1D(GL_TEXTURE_1D, 0, 0, img_animate.x, 1124: GL_RGB, GL_UNSIGNED_BYTE,img_animate.data); 1125: glBindTexture(GL_TEXTURE_1D, 0); 1126: 1127:} 1128: 1129:////////////////////////////////////////////////////////////////////////////// 1130:// 1131:// Render the current frame 1132:// - Draws everything as computed in last advanceFrame, updates nothing 1133:// 1134:// RETURN: true on success (always) 1135:////////////////////////////////////////////////////////////////////////////// 1136:bool CMotherboard::renderFrame() 1137:{ 1138: // These are used as backups when fading the light out 1139: fRGBA l0Ambient,l0Diffuse,l0Specular; int l0Shininess; 1140: fRGBA lsAmbient,lsDiffuse,lsSpecular; int lsShininess; 1141: 1142: // Camera 1143: glMatrixMode(GL_MODELVIEW); // Reset modelview matrix 1144: glLoadIdentity(); 1145: flight.cam.execute(); // Apply camera transform 1146: frustum.setFrustum(flight.cam); // Rotate view frustum according to camera 1147: 1148: // If we are in fadeout mode, fade the lights to a lower level 1149: if (nElapsedTime>=FADESTART) { 1150: // Calculate fade factor from 0..1 1151: float fFadeFactor = calcFactor(nElapsedTime,FADESTART,FADETIME); 1152: 1153: // Save light settings 1154: l0Ambient = light0.ambient; lsAmbient = lightSocket.ambient; 1155: l0Diffuse = light0.diffuse; lsDiffuse = lightSocket.diffuse; 1156: l0Specular= light0.specular; lsSpecular= lightSocket.specular; 1157: l0Shininess=light0.shininess; lsShininess=lightSocket.shininess; 1158: 1159: // Fade out scaled light settings according to fade factor computed above 1160: fFadeFactor = 1-fFadeFactor; 1161: light0.ambient = l0Ambient*fFadeFactor; 1162: light0.diffuse = l0Diffuse*fFadeFactor; 1163: light0.specular= l0Specular*fFadeFactor; 1164: lightSocket.ambient = lsAmbient*fFadeFactor; 1165: lightSocket.diffuse = lsDiffuse*fFadeFactor; 1166: lightSocket.specular= lsSpecular*fFadeFactor; 1167: 1168: // If we are in the final fadeout, fade the saved lights too, not just the copies 1169: if (nElapsedTime>=FINALSTART) 1170: { 1171: float fRate = (1.0f/30.0f) * (FINALTIME / 1000.0f); // Speed of final fade down 1172: l0Ambient -= fwhite*fRate*m_oEnvInfo.fFrameFactor; lsAmbient -= -->fwhite*fRate*m_oEnvInfo.fFrameFactor; 1173: l0Diffuse -= fwhite*fRate*m_oEnvInfo.fFrameFactor; lsDiffuse -= -->fwhite*fRate*m_oEnvInfo.fFrameFactor; 1174: l0Specular -= fwhite*fRate*m_oEnvInfo.fFrameFactor; lsSpecular -= -->fwhite*fRate*m_oEnvInfo.fFrameFactor; 1175: l0Shininess-= fRate*m_oEnvInfo.fFrameFactor; lsShininess-= fRate*m_oEnvInfo. -->fFrameFactor; 1176: } 1177: } 1178: ////////// BEGIN STUFF THAT WILL BE AFFECTED BY THE FIRST FADEOUT ////////// 1179: 1180: // Apply light position & color 1181: light0.executeLight(); 1182: lightSocket.executeLight(); 1183: 1184: // Draw static objects 1185: drawVisibleObject(computer); // Computer case 1186: drawVisibleObject(motherboard); // Motherboard plane 1187: drawVisibleObject(coolchip); // Big chip near CPU socket (credits on it) 1188: drawVisibleObject(RAM); // Memory chip 1189: drawVisibleObject(AGP); // AGP, ISA slots 1190: drawVisibleObject(ISA); 1191: 1192: // Multiple static objects 1193: int nObject; 1194: for (nObject=0; nObject<num_Res; nObject++) drawVisibleObject(resistor[nObject]); 1195: for (nObject=0; nObject<num_Cap; nObject++) drawVisibleObject(capacitor[nObject]); 1196: for (nObject=0; nObject<num_PCI; nObject++) drawVisibleObject(PCI[nObject]); 1197: for (nObject=0; nObject<num_DIMM; nObject++) drawVisibleObject(DIMM[nObject]); 1198: for (nObject=0; nObject<num_Chip; nObject++) drawVisibleObject(microchip[nObject]); 1199: 1200: /////////// END STUFF THAT WILL BE AFFECTED BY THE FIRST FADEOUT //////////// 1201: 1202: // Okay, now there are a few things that we want drawn even if the light is out 1203: // So restore the light 1204: if (nElapsedTime>=FADESTART) { 1205: // Bring back light from saved values 1206: light0.ambient = l0Ambient; 1207: light0.diffuse = l0Diffuse; 1208: light0.specular= l0Specular; 1209: lightSocket.ambient = lsAmbient; 1210: lightSocket.diffuse = lsDiffuse; 1211: lightSocket.specular= lsSpecular; 1212: 1213: // Re-apply the lights 1214: light0.executeLight(); 1215: lightSocket.executeLight(); 1216: } 1217: 1218: // Static objects not affected by the first fade out 1219: drawVisibleObject(socketHandle); // Movable handle to CPU socket 1220: drawVisibleObject(socket); // CPU socket 1221: drawVisibleObject(CPUchip); // CPU chip 1222: 1223: // Transparent objects, effects 1224: // - Disable writing to the depth buffer 1225: glDepthMask(GL_FALSE); 1226: 1227: // Draw flare of light that grows out from the CPU socket, along the motherboard 1228: flare.execute(); 1229: 1230: // Draw light beam etching mindware logo onto CPU chip 1231: // - Only if the time is right 1232: if (nElapsedTime>ANIMSTART && nElapsedTime<ANIMSTART+ANIMTIME) 1233: lightBeam.execute(); 1234: 1235: // Draw glowing column of light & the little whisps 1236: // - Only if the time is right 1237: if (nElapsedTime>GLOWSTART && nElapsedTime<CHIPSTART+CHIPTIME) 1238: { 1239: // Draw the column 1240: glowing.execute(); 1241: // Draw the whisps 1242: for (nObject=0; nObject<nWhispy; nObject++) 1243: whispy[nObject].execute(); 1244: } 1245: 1246: // Draw bump map on motherboard 1247: if (m_szBumpFile) 1248: motherboardBump.execute(); 1249: 1250: /* Glowing sphere 1251: /* 1252: -- This is commented out by popular demand. I really liked it because you could see 1253: what was causing the light. But no matter what I did, it looked lame. So it is 1254: removed. 1255: glPushMatrix(); 1256: // No texture, enable additive blending 1257: glBindTexture(GL_TEXTURE_2D,0); 1258: glEnable(GL_BLEND); 1259: glBlendFunc(GL_SRC_ALPHA, GL_ONE); 1260: glTranslatef(light0.position.x,light0.position.y,light0.position.z); 1261: 1262: // White, vary 40%-60% transparency 1263: glMaterialfv(GL_FRONT,GL_AMBIENT,fRGBA(0,0,0,1)); 1264: glMaterialfv(GL_FRONT,GL_DIFFUSE,fRGBA(0,0,0,frand01()*0.2f + 0.4f)); 1265: glMaterialfv(GL_FRONT,GL_SPECULAR,fRGBA(0,0,0,1)); 1266: glMaterialfv(GL_FRONT,GL_EMISSION,fRGBA(1,1,1,1)); 1267: 1268: // Draw sphere 1269: GLUquadricObj *qoSphere = gluNewQuadric(); 1270: gluQuadricTexture(qoSphere, GL_FALSE); 1271: gluQuadricDrawStyle(qoSphere, GLU_FILL); 1272: gluSphere(qoSphere, 0.5f, 10, 10); 1273: gluDeleteQuadric(qoSphere); 1274: 1275: glDisable(GL_BLEND); 1276: glPopMatrix(); 1277: */ 1278: 1279: // Draw debugging info if in debug mode 1280: #ifdef _DEBUG 1281: if (m_oEnvInfo.bShowDebugInfo) 1282: { 1283: glMaterialfv(GL_FRONT,GL_EMISSION,white); 1284: m_oEnvInfo.OglDebug.printf(0,48,0,"start: %d, frame: %d",nTimeStart,flight.nFrame); 1285: glMaterialfv(GL_FRONT,GL_EMISSION,black); 1286: glMaterialfv(GL_FRONT,GL_EMISSION,fwhite); 1287: m_oEnvInfo.OglDebug.printf(0,48,0,"start: %d, frame: %d",nTimeStart,flight.getFrame()); 1288: glMaterialfv(GL_FRONT,GL_EMISSION,fblack); 1289: } 1290: #endif 1291: 1292: // Re-enable the depth mask 1293: glDepthMask(GL_TRUE); 1294: 1295: // This is unneeded 1296: glFlush(); 1297: 1298: return true; 1299:} 1300: 1301:////////////////////////////////////////////////////////////////////////////// 1302:// 1303:// Advance the animation for the motherboard effect 1304:// - Computes the procedural texture img_mindware and sends it to opengl 1305:// - Computes the procedural 1D texture for the "etching" light beam 1306:// 1307:// RETURNS: true for success (always) 1308:////////////////////////////////////////////////////////////////////////////// 1309:bool CMotherboard::advanceFrame() 1310:{ 1311: // Update elapsed time 1312: nElapsedTime = m_oEnvInfo.getMusicTime() - nTimeStart; 1313: 1314: // Apply motion set during manual control 1315:#ifdef MANUAL_CONTROL 1316: flight.cam.position += motion; // Apply movement, rotation vectors 1317: flight.cam.rotateDeg(rotation); 1318: motion = motion/2; // Slow down motion, rotation 1319: rotation= rotation/2; 1320:#else 1321: // Tell the fly-through the new time - it will update position accordingly 1322: flight.setCamera(nElapsedTime); 1323:#endif 1324: 1325: // CPU chip falling 1326: if (nElapsedTime>=CHIPSTART) 1327: { 1328: // Compute factor 0..1, and new chip position 1329: float fChipFactor = calcFactor(nElapsedTime,CHIPSTART,CHIPTIME); 1330: CPUchip.position = socket.position + fVector3D(0,0,100*(1-fChipFactor)+1); 1331: } 1332: 1333: // Do glowing socket stuff 1334: // (do this after the chip falls because glowingBurst() references the chip position) 1335: if (nElapsedTime>=GLOWSTART && nElapsedTime<CHIPSTART+CHIPTIME) { 1336: // Glowing factor 0...1 1337: float fGlowFactor = calcFactor(nElapsedTime,GLOWSTART,GLOWTIME); 1338: 1339: // Drawing the burst of light 1340: advanceGlowingBurst(fGlowFactor); 1341: 1342: // Drawing the whisps of light 1343: for (int i=0; i<nWhispy; i++) { 1344: if (whispy[i].position.z >= CPUchip.position.z - WHISP_SIZE*2) { 1345: whispyData[i].reset(); 1346: whispy[i].objects[0].emission(0.3f,frand01()+0.3f,frand01()+0.3f,1); 1347: } 1348: whispyData[i].advance(m_oEnvInfo.fFrameFactor); 1349: whispy[i].objects[0].diffuse(0,0,0,whispyData[i].bright); 1350: whispy[i].position = motherboard.position + fVector3D(0,49,0) + whispyData[i].fluxPos; 1351: } 1352: } 1353: 1354: // Socket handle returns after chip falls 1355: if (nElapsedTime>=CHIPSTART+CHIPTIME) { 1356: float fSockFactor = calcFactor(nElapsedTime,CHIPSTART+CHIPTIME,GLOWTIME); 1357: 1358: socketHandle.direction(0,fSockFactor*-90,0); 1359: } 1360: 1361: // Chip logo appears 1362: if (nElapsedTime>=ANIMSTART) { 1363: float fAnimFactor = calcFactor(nElapsedTime,ANIMSTART,ANIMTIME); 1364: 1365: advanceChipTexture(fAnimFactor); 1366: } 1367: 1368: // Light source is 10 units ahead of the camera position 1369: light0.position = flight.cam.position + flight.cam.getForward() * LIGHT_FWD_DIST; 1370: light0.position.z = motherboard.position.z + LIGHT_HOVER_Z; 1371: 1372: // Update light map 1373: advanceLightMap(); 1374: return true; 1375:}; 1376: 1377:////////////////////////////////////////////////////////////////////////////// 1378:// 1379:// Animate glowing from CPU socket 1380:// - Advance the column of light from the CPU socket 1381:// - Enlarge the flare from the CPU socket 1382:// 1383:// ARGS: fGlowFactor, 0..1 (0 is starting, 1 is completed) 1384:////////////////////////////////////////////////////////////////////////////// 1385:void CMotherboard::advanceGlowingBurst(float fGlowFactor) 1386:{ 1387: Object3D &glowObj = glowing.objects[0]; // Working column of light 1388: Object3D &glowOld = glowingOld.objects[0]; // Original column of light 1389: 1390: // First half of flare is fast 1391: if (fGlowFactor<0.50f) { 1392: if (fGlowFactor>0.01f) // Don't scale below a certain size 1393: flare.scale(fGlowFactor*1000); // or it goofs up 1394: flare.objects[0].diffuse(0,0,0,fGlowFactor*2); 1395: } else 1396: // Second half of flare is really fast 1397: if (fGlowFactor<1.00f) { 1398: flare.scale(500 + (fGlowFactor-0.5f)*2500); 1399: flare.objects[0].diffuse(0,0,0,(1-fGlowFactor)*2); 1400: } 1401: // Rotate the flare for effect 1402: flare.direction = fVector3D(0,0,fGlowFactor*360); 1403: 1404: // Apply the light coming from the socket 1405: // - This yellowish light floats up from the motherboard to just above the socket 1406: // - It flickers randomly, and only affects very nearby objects (due to attenuation) 1407: lightSocket.on(); 1408: lightSocket.setLight(fGlowFactor,fGlowFactor,fGlowFactor,64,fRGBA(1,1,0)); 1409: lightSocket.position = motherboard.position + fVector3D(0,49,1 + fGlowFactor*5); 1410: glLightf(GL_LIGHT0+lightSocket.nLightID,GL_LINEAR_ATTENUATION,0.05f+frand01()*0.025f); 1411: 1412: // Turn the socket handle 1413: socketHandle.direction(0,fGlowFactor*90 - 90,0); 1414: 1415: // The glowing column of light has the alpha value randomly fluctuate by 10% 1416: // - It grows upward (z+) from the original position 1417: glowObj.diffuse(0,0,0,fGlowFactor/4+frand01()*0.1f); 1418: float fHeight = CPUchip.position.z - glowing.position.z - 1; 1419: glowObj.points[2].y = glowOld.points[2].y + fGlowFactor*fHeight; 1420: glowObj.points[3].y = glowOld.points[3].y + fGlowFactor*fHeight; 1421: glowObj.points[6].y = glowOld.points[6].y + fGlowFactor*fHeight; 1422: glowObj.points[7].y = glowOld.points[7].y + fGlowFactor*fHeight; 1423:} 1424: 1425:/********************************** CWhisp ***********************************/ 1426: 1427:////////////////////////////////////////////////////////////////////////////// 1428:// 1429:// Reset a whisp 1430:// - Move to a random position at the base of the socket 1431:// - Pick random speeds and motions 1432:////////////////////////////////////////////////////////////////////////////// 1433:void CWhisp::reset() 1434:{ 1435: // Place somewhere within the socket, directly on the motherboard 1436: basePos = fVector3D(frand11()*SOCKET_XSIZE, frand11()*SOCKET_YSIZE, 0); 1437: // Reset flux animation factor 1438: fluxCnt = 0; 1439: // Pick a vertical motion speed and a speed for fluxiness 1440: zSpeed = frand01() * 1.0f + 0.4f; 1441: rSpeed = frand01() * 0.3f + 0.1f; 1442: 1443: // Pick a direction 0 - 360 degrees for the particle to fluctuate 1444: float fluxDeg = rand() % 360; 1445: fluxDir(sinf(DtoR(fluxDeg)), cosf(DtoR(fluxDeg)), 0); 1446: // Brightness starts at fully transparent 1447: bright = 0.0f; 1448:} 1449: 1450:////////////////////////////////////////////////////////////////////////////// 1451:// 1452:// Advance the animation for a CWhisp 1453:// - Moves object position, updates brightness 1454:// 1455:// ARGS: fFrameFactor, 0..1 (0 is starting, 1 is completed) 1456:////////////////////////////////////////////////////////////////////////////// 1457:void CWhisp::advance(float fFrameFactor) 1458:{ 1459: // Move whisp according to whispy speed and frame rate 1460: basePos.z += zSpeed * fFrameFactor; // Move along z axis 1461: fluxCnt += rSpeed * fFrameFactor; // Swirl along xy axis 1462: 1463: // Final position is base position + fluxing position * fluxiness 1464: fluxPos = basePos + fluxDir * sinf(fluxCnt) * FLUXINESS; 1465: 1466: // Make brighter, unless at max brightness 1467: if (bright>=1) 1468: bright = 1; 1469: else 1470: bright += zSpeed * 0.05f * fFrameFactor; 1471:} 1472: 1473:/*** This will be replaced with something else later 1474: 1475:???WHG??? Implement array of pressed keys in CVidGLDerive 1476: 1477:bool CMotherboard::keyEvent(int nKey, bool bPress) 1478:{ 1479: if (!bPress) 1480: return true; 1481: 1482: Camera3D &cam = flight.cam; 1483: 1484: switch(nKey) { 1485: case VK_ESCAPE: 1486: endGL(); 1487: break; 1488: 1489: case '0': flight.start(); break; 1490:#ifdef _DEBUG 1491: case '1': std::cout << cam.position.x << "," 1492: << cam.position.y << "," 1493: << cam.position.z << std::endl; 1494: std::cout << cam.getDirection().x << "," 1495: << cam.getDirection().y << "," 1496: << cam.getDirection().z << "," 1497: << cam.getDirection().w << std::endl; 1498: break; 1499:#endif 1500: 1501: case 'W': motion += cam.getForward()*MOTIONSPEED; break; 1502: case 'S': motion -= cam.getForward()*MOTIONSPEED; break; 1503: case 'A': motion += cam.getSideways()*MOTIONSPEED; break; 1504: case 'D': motion -= cam.getSideways()*MOTIONSPEED; break; 1505: case 'Q': motion += cam.getUpward()*MOTIONSPEED; break; 1506: case 'Z': motion -= cam.getUpward()*MOTIONSPEED; break; 1507: 1508: case VK_UP: rotation.x -= 1.0f; break; 1509: case VK_DOWN: rotation.x += 1.0f; break; 1510: case VK_RIGHT: rotation.y += 1.0f; break; 1511: case VK_LEFT: rotation.y -= 1.0f; break; 1512: case VK_HOME :rotation.z -= 1.0f; break; 1513: case VK_PRIOR :rotation.z += 1.0f; break; 1514: } 1515: 1516: return true; 1517:} 1518: 1519:***/ 1520:
Statistics:
Unchanged lines: | 1391 |
Deleted lines: | 98 |
Inserted lines: | 30 |
Lines in diff: | 1519 |
Lines in first text: | 1489 |
Lines in second text: | 1421 |