//----------------------------------------------------------------------------- // set day or night void Landscape::setDayLight( BOOL daylight) { m_daylight = daylight; m_sky->enableFog(true); if (m_daylight) { m_lightColor = mgPoint3(0.8, 0.8, 0.8); m_fogColor = mgPoint3(0.8, 0.8, 0.8); } else { m_lightColor = mgPoint3(0.2, 0.2, 0.2); m_fogColor = mgPoint3(0.2, 0.2, 0.2); } m_sky->enableSkyBox(m_daylight); m_sky->enableSun(m_daylight); m_sky->enableStars(!m_daylight); m_sky->enableMoon(!m_daylight); m_eyeChanged = true; }
//-------------------------------------------------------------- // constructor Planet::Planet( const mgOptionsFile& options) { // load the planet cubemap texture mgString xminName, xmaxName, yminName, ymaxName, zminName, zmaxName; options.getFileName("planet-xmin", options.m_sourceFileName, "", xminName); options.getFileName("planet-xmax", options.m_sourceFileName, "", xmaxName); options.getFileName("planet-ymin", options.m_sourceFileName, "", yminName); options.getFileName("planet-ymax", options.m_sourceFileName, "", ymaxName); options.getFileName("planet-zmin", options.m_sourceFileName, "", zminName); options.getFileName("planet-zmax", options.m_sourceFileName, "", zmaxName); m_surfaceTexture = loadCubeMap(xminName, xmaxName, yminName, ymaxName, zminName, zmaxName); // load the clouds cubemap texture options.getFileName("clouds-xmin", options.m_sourceFileName, "", xminName); options.getFileName("clouds-xmax", options.m_sourceFileName, "", xmaxName); options.getFileName("clouds-ymin", options.m_sourceFileName, "", yminName); options.getFileName("clouds-ymax", options.m_sourceFileName, "", ymaxName); options.getFileName("clouds-zmin", options.m_sourceFileName, "", zminName); options.getFileName("clouds-zmax", options.m_sourceFileName, "", zmaxName); m_cloudsTexture = loadCubeMap(xminName, xmaxName, yminName, ymaxName, zminName, zmaxName); compileShader(options); // create the vertex buffer glGenVertexArrays(1, &m_vertexArray); glBindVertexArray(m_vertexArray); glGenBuffers(1, &m_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexPlanet), (const GLvoid*) offsetof(VertexPlanet, m_px)); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexPlanet), (const GLvoid*) offsetof(VertexPlanet, m_mx)); m_eyePt = mgPoint3(3500, 0, 0); m_eyeRotX = 0.0; m_eyeRotY = 90.0; m_eyeMatrix.rotateYDeg(m_eyeRotY); m_eyeMatrix.rotateXDeg(m_eyeRotX); m_specularColor = mgPoint3(0.4, 0.4, 0.4); m_lightColor = mgPoint3(0.6, 0.6, 0.6); m_lightAmbient = mgPoint3(0.2, 0.2, 0.2); m_matColor = mgPoint4(1, 1, 1, 1); }
//-------------------------------------------------------------- // constructor SolarSystem::SolarSystem( const mgOptionsFile& options) { m_planetDayLen = options.getDouble("planetDayLen", 600.0); // seconds if (m_planetDayLen == 0.0) m_planetDayLen = 1e10; // infinity m_moonDayLen = options.getDouble("moonDayLen", 300.0); // seconds if (m_moonDayLen == 0.0) m_moonDayLen = 1e10; // infinity m_ringDayLen = options.getDouble("ringDayLen", 200.0); // seconds if (m_ringDayLen == 0.0) m_ringDayLen = 1e10; // infinity m_moonMonthLen = options.getDouble("moonMonthLen", 1000.0); // seconds if (m_moonMonthLen == 0.0) m_moonMonthLen = 1e10; // infinity m_beltMonthLen = options.getDouble("beltMonthLen", 1000.0); // seconds if (m_beltMonthLen == 0.0) m_beltMonthLen = 1e10; // infinity m_planet = new Planet(options, PLANET_RADIUS); // m_belt = new Belt(options, BELT_RADIUS); m_moon = new Moon(options, MOON_RADIUS); m_ring = new Ring(options, RING_RADIUS, RING_WALL_HEIGHT, RING_WALL_WIDTH); m_planetDay = 90.0; m_moonDay = 0.0; m_ringDay = 0.0; m_moonMonth = 30.0; m_beltMonth = 0.0; m_coordSystem = COORDS_PLANET; m_coordPosn = mgPoint3(0.0, 2.0, 0.0); m_eyeRotX = 0.0; m_eyeRotY = 0.0; m_eyeRotZ = 0.0; mgDebug("Planet radius = %g km (%g miles)", PLANET_RADIUS/1000.0, PLANET_RADIUS/1600.0); double val = 4*PI*PLANET_RADIUS*PLANET_RADIUS; mgDebug("Surface area of planet = %g million sq km (%g million sq mi)", val/1e12, (val/1e12)/1.609); mgDebug("Moon radius = %g km (%g miles)", MOON_RADIUS/1000.0, MOON_RADIUS/1600.0); val = 4*PI*MOON_RADIUS*MOON_RADIUS; mgDebug("Surface area of moon = %g million sq km (%g million sq mi)", val/1e12, (val/1e12)/1.609); mgDebug("Moon distance = %g km (%g miles)", MOON_DISTANCE/1000.0, MOON_DISTANCE/1600.0); mgDebug("Ring radius = %g km (%g miles)", RING_RADIUS/1000.0, RING_RADIUS/1600.0); val = 2*PI*RING_RADIUS*RING_WIDTH; mgDebug("Surface area of ring = %g million sq km (%g million sq mi)", val/1e12, (val/1e12)/1.609); mgDebug("Ring width = %g m (%g ft)", RING_WIDTH, RING_WIDTH*3.16); mgDebug("Ring wall height = %g m (%g ft)", RING_WALL_HEIGHT, RING_WALL_HEIGHT*3.16); mgDebug("Ring wall width = %g m (%g ft)", RING_WALL_WIDTH, RING_WALL_WIDTH*3.16); }
//-------------------------------------------------------------- // initialize application void SeaOfMemes::appInit() { // get the important directories mgString shaderDir; m_options.getFileName("shaderDir", m_options.m_sourceFileName, "docs/shaders", shaderDir); mgString uiDir; m_options.getFileName("uiDir", m_options.m_sourceFileName, "docs/ui", uiDir); mgString fontDir; m_options.getFileName("fontDir", m_options.m_sourceFileName, "docs/fonts", fontDir); mgInitDisplayServices(shaderDir, fontDir); mgDisplay->setDPI(m_options.getInteger("dpi", 0)); mgDisplay->setFOV(m_options.getDouble("FOV", 60.0)); // load cursors loadCursor(); setDeskMode(true); // take units from option m_unitsMetric = m_options.getBoolean("metricUnits", true); // create the sky m_matColor = mgPoint3(1, 1, 1); m_lightDir = mgPoint3(1.0, 0.25, 0.0); m_lightDir.normalize(); m_sky = new NebulaSky(m_options); m_sky->setSunDir(m_lightDir); m_world = new SolarSystem(m_options); m_helpUI = new HelpUI(m_options); m_helpUI->setDebugApp(this); m_speedUI = new SpeedUI(m_options); m_speedUI->setUnits(m_unitsMetric ? UNITS_KM : UNITS_MILES); appCreateBuffers(); // initialize movement initMovement(); m_lastAnimate = 0.0; }
//-------------------------------------------------------------- // return end of array void mgPoint3Array::top( mgPoint3& elm) const { if (m_elementCount == 0) { elm = mgPoint3(0, 0, 0); return; } elm = m_elements[m_elementCount-1]; }
//-------------------------------------------------------------- // return element of array void mgPoint3Array::getAt( int index, mgPoint3& elm) const { if (index < 0 || index >= m_elementCount) { elm = mgPoint3(0, 0, 0); return; } elm = m_elements[index]; }
//-------------------------------------------------------------- // constructor Planet::Planet( const mgOptionsFile& options) { // load the planet cubemap texture mgString xminName, xmaxName, yminName, ymaxName, zminName, zmaxName; options.getFileName("planet-xmin", options.m_sourceFileName, "", xminName); options.getFileName("planet-xmax", options.m_sourceFileName, "", xmaxName); options.getFileName("planet-ymin", options.m_sourceFileName, "", yminName); options.getFileName("planet-ymax", options.m_sourceFileName, "", ymaxName); options.getFileName("planet-zmin", options.m_sourceFileName, "", zminName); options.getFileName("planet-zmax", options.m_sourceFileName, "", zmaxName); m_surfaceTexture = loadCubeMap(xminName, xmaxName, yminName, ymaxName, zminName, zmaxName); // load the clouds cubemap texture options.getFileName("clouds-xmin", options.m_sourceFileName, "", xminName); options.getFileName("clouds-xmax", options.m_sourceFileName, "", xmaxName); options.getFileName("clouds-ymin", options.m_sourceFileName, "", yminName); options.getFileName("clouds-ymax", options.m_sourceFileName, "", ymaxName); options.getFileName("clouds-zmin", options.m_sourceFileName, "", zminName); options.getFileName("clouds-zmax", options.m_sourceFileName, "", zmaxName); m_cloudsTexture = loadCubeMap(xminName, xmaxName, yminName, ymaxName, zminName, zmaxName); compileShader(options); // create the vertex buffer glGenBuffers(1, &m_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); m_eyePt = mgPoint3(3500, 0, 0); m_eyeRotX = 0.0; m_eyeRotY = 90.0; m_eyeMatrix.rotateYDeg(m_eyeRotY); m_eyeMatrix.rotateXDeg(m_eyeRotX); m_specularColor = mgPoint3(0.4, 0.4, 0.4); m_lightColor = mgPoint3(0.6, 0.6, 0.6); m_lightAmbient = mgPoint3(0.2, 0.2, 0.2); m_matColor = mgPoint4(1, 1, 1, 1); }
//-------------------------------------------------------------- // remove from end of array void mgPoint3Array::pop( mgPoint3& elm) { if (m_elementCount == 0) { elm = mgPoint3(0, 0, 0); return; } elm = m_elements[m_elementCount-1]; m_elementCount--; }
//-------------------------------------------------------------- // set element of array void mgPoint3Array::setAt( int index, const mgPoint3& elm) { grow(index); // pad to position of new element for (int i = m_elementCount; i < index; i++) m_elements[i] = mgPoint3(0, 0, 0); // set new element m_elements[index] = elm; m_elementCount = max(m_elementCount, index+1); }
//-------------------------------------------------------------- // add a branch void Colonization::addBranch( const mgPoint3& pt, int parent) { Branch* branch = new Branch(); branch->m_pt = pt; branch->m_parent = parent; branch->m_growDir = mgPoint3(0, 0, 0); branch->m_growCount = 0; branch->m_area = TWIG_AREA; m_branches.add(branch); }
//-------------------------------------------------------------- // constructor ChunkWorld::ChunkWorld( const mgOptionsFile& options) { BrickBlob::staticInit(); loadShaders(); // read the brick set to use mgString fileName; options.getFileName("brickSet", options.m_sourceFileName, "bricks.xml", fileName); BrickSetFile brickSetFile(fileName); readBrickSet(brickSetFile); loadWaterTexture(brickSetFile); m_textureArray = mgDisplay->loadTextureArray(m_textureFiles); m_displayMemLimit = options.getInteger("displayMemory", 200); m_displayMemLimit *= 1024*1024; // megabytes m_systemMemLimit = options.getInteger("systemMemory", 400); m_systemMemLimit *= 1024*1024; // megabytes m_threadCount = options.getInteger("threadCount", 1); #ifdef EMSCRIPTEN m_threadCount = 0; #endif m_viewDistance = options.getInteger("viewDistance", 300); // since the view list goes up as the cube of distance, limit it m_viewDistance = min(450, m_viewDistance); m_sortCount = options.getInteger("sortCount", 5); options.getPoint("torchColor", mgPoint3(0.5, 0.5, 0.1), m_torchColor); mgDebug("thread count: %d", m_threadCount); m_viewList = NULL; createViewList(m_viewDistance); createHorizon(); createWater(); m_displayMemUsed = 0; m_systemMemUsed = 0; m_shutdown = false; m_chunksChanged = false; createWorkers(); }
//----------------------------------------------------------------------------- // call a function void TestCube::debugCallFunction( const char* funcName, mgStringArray& args, mgString& reply) { // process function call if (_stricmp(funcName, "reset") == 0) { m_eyePt = mgPoint3(0, 2.5, -3.5); m_eyeRotX = 0.0; m_eyeRotY = 0.0; m_eyeRotZ = 0.0; m_eyeChanged = true; reply = "ok"; } else MovementApp::debugCallFunction(funcName, args, reply); }
//-------------------------------------------------------------------- // initialize movement state void SeaOfMemes::initMovement() { m_forwardSince = INVALID_TIME; m_backwardSince = INVALID_TIME; m_leftSince = INVALID_TIME; m_rightSince = INVALID_TIME; m_upSince = INVALID_TIME; m_downSince = INVALID_TIME; m_turnLeftSince = INVALID_TIME; m_turnRightSince = INVALID_TIME; m_turnSpeed = 120.0/1000; // degrees per ms m_landingMode = false; m_targetSpeed = MAX_AVATAR_SPEED; m_avatarSpeed = m_targetSpeed; m_world->setCoordSystem(COORDS_SPACE); m_world->setCoordPosn(mgPoint3(PLANET_RADIUS*2, 0.0, 0.0)); // m_world->setCoordSystem(COORDS_RING); // m_world->setCoordPosn(mgPoint3(RING_RADIUS-1000, 0.0, 0.0)); // m_world->setCoordSystem(COORDS_PLANET); // double angle = 45*PI/180; // double ht = PLANET_RADIUS+1000.0; // m_world->setCoordPosn(mgPoint3(ht*sin(angle), ht*cos(angle), 0.0)); // m_world->setCoordSystem(COORDS_MOON); // double angle = 45*PI/180; // double ht = MOON_RADIUS+1000.0; // m_world->setCoordPosn(mgPoint3(ht*sin(angle), ht*cos(angle), 0.0)); m_world->setEyeAngle(0.0, 0.0); if (m_speedUI != NULL) { m_speedUI->setSpeed(m_avatarSpeed); m_speedUI->setLanding(false); } m_eyeChanged = true; }
//-------------------------------------------------------------------- // initialize movement state void GuiTestAll::initMovement() { m_forwardSince = INVALID_TIME; m_backwardSince = INVALID_TIME; m_leftSince = INVALID_TIME; m_rightSince = INVALID_TIME; m_upSince = INVALID_TIME; m_downSince = INVALID_TIME; m_turnLeftSince = INVALID_TIME; m_turnRightSince = INVALID_TIME; m_turnSpeed = 120.0/1000; // degrees per ms m_moveSpeed = 2.5/1000; // units per ms // 100.0/1000; m_eyePt = mgPoint3(0, 2.5, -3.5); m_eyeRotX = 0.0; m_eyeRotY = 0.0; m_eyeRotZ = 0.0; m_eyeChanged = true; }
//-------------------------------------------------------------- // initialize application void Crafty::appInit() { MovementApp::appInit(); mgPlatform->setWindowTitle("Crafty, Part 58"); // get lighting and material m_options.getPoint("matColor", mgPoint3(1,1,1), m_matColor); m_options.getPoint("sunlightColor", mgPoint3(0.8, 0.8, 0.8), m_sunlightColor); m_options.getPoint("moonlightColor", mgPoint3(0.1, 0.1, 0.1), m_moonlightColor); m_options.getPoint("torchlightColor", mgPoint3(0.5, 0.5, 0.5), m_torchlightColor); // since the view list goes up as the cube of distance, limit it int viewDistance = m_options.getInteger("viewDistance", 300); viewDistance = min(450, viewDistance); m_fogMaxDist = viewDistance; // create the sky m_lightDir = mgPoint3(0.0, 0.5, 1.0); m_sky = new StarrySky(m_options); m_sky->setMoonDir(m_lightDir); m_sky->setSunDir(m_lightDir); m_sky->setFogInten(1.0, 1.0); m_sky->setFogDist(1000.0, m_fogMaxDist); m_world = new ChunkWorld(m_options); m_world->setTorchColor(m_torchlightColor); m_world->setFogHeight(FOG_BOT_HEIGHT, FOG_TOP_HEIGHT); m_world->setFogInten(1.0, 1.0); m_world->setFogDist(m_fogMaxDist); setDaylight(true); setFoggy(true); m_eyePt = mgPoint3(721, 72, -179); m_eyeRotX = -1.32; // -33; m_eyeRotY = -111.56; // -29; m_eyeRotZ = 0; setDeskMode(true); // create the help pane m_help = new HelpUI(m_options); setUI(m_help); }
//-------------------------------------------------------------------- // render the view void Crafty::appViewDraw() { // draw the sky mgDisplay->setFrontAndBack(0.25, 16384); mgMatrix4 identity; m_eyeMatrix.loadIdentity(); m_eyeMatrix.rotateZDeg(m_eyeRotZ); m_eyeMatrix.rotateYDeg(m_eyeRotY); m_eyeMatrix.rotateXDeg(m_eyeRotX); mgDisplay->setEyeMatrix(m_eyeMatrix); mgDisplay->setEyePt(mgPoint3(0,0,0)); mgDisplay->setModelTransform(identity); mgDisplay->setCulling(true); m_sky->setFogHeight(FOG_BOT_HEIGHT - m_eyePt.y, FOG_TOP_HEIGHT - m_eyePt.y); m_sky->render(); // reset state after any changes in sky render mgDisplay->setLightDir(m_lightDir.x, m_lightDir.y, m_lightDir.z); mgDisplay->setMatColor(m_matColor.x, m_matColor.y, m_matColor.z); mgDisplay->setLightAmbient(0.0, 0.0, 0.0); mgDisplay->setTransparent(false); mgDisplay->setEyeMatrix(m_eyeMatrix); mgDisplay->setEyePt(m_eyePt); mgDisplay->setModelTransform(identity); m_world->render(); mgDisplay->setTransparent(true); m_world->renderTransparent(); mgDisplay->setTransparent(false); }
//-------------------------------------------------------------------- // render the view void SeaOfMemes::appViewDraw() { // draw the sky mgDisplay->setFrontAndBack(0.25, 16384); mgPoint3 eyePt; m_world->getEyePt(eyePt); mgMatrix4 eyeMatrix; m_world->getEyeMatrix(eyeMatrix); mgDisplay->setEyeMatrix(eyeMatrix); mgDisplay->setEyePt(mgPoint3(0,0,0)); mgMatrix4 identity; mgDisplay->setModelTransform(identity); mgDisplay->setCulling(true); m_sky->render(); m_world->setSunDir(m_lightDir); m_world->render(); }
//----------------------------------------------------------------------------- // create ring void Wreck::createRing( mgMatrix4& xform, int ringSteps, int circleSteps) { mgBezier ringSpline; ringSpline.addVertex(mgPoint3( 0.0, 4.0, 0.0), mgPoint3( 0.0+13, 4.0, 0.0)); ringSpline.addVertex(mgPoint3( 13.0, 0.0, 0.0), mgPoint3( 13.0, 0.0+4, 0.0)); ringSpline.addVertex(mgPoint3( 0.0, -4.0, 0.0), mgPoint3( 0.0+13, -4.0, 0.0)); double ringLen = ringSpline.getLength(); mgVertexTA* points = new mgVertexTA[(ringSteps+1) * (circleSteps+1)]; mgPoint3 ringPt, xpt; for (int i = 0; i <= circleSteps; i++) { double angle = (i*2*PI)/circleSteps; for (int j = 0; j <= ringSteps; j++) { ringSpline.splinePt((ringLen * j)/ringSteps, ringPt); mgVertexTA* v = &points[i*(ringSteps+1)+j]; mgPoint3 pt(cos(angle) * ringPt.x, sin(angle) * ringPt.x, ringPt.y); xform.mapPt(pt, xpt); v->setPoint(xpt.x, xpt.y, xpt.z); v->setTexture(xpt.z/100 + 2*j/(double) ringSteps, 2*i/(double) circleSteps, 0); } } // set all the normals setNormals(points, circleSteps+1, ringSteps+1, true); int vertexBase = m_vertexes->getLength(); for (int i = 0; i < (circleSteps+1)*(ringSteps+1); i++) m_vertexes->addVertex(&points[i]); m_indexes->addGrid(vertexBase, ringSteps+1, circleSteps, ringSteps, true); delete points; }
//----------------------------------------------------------------------------- // create vertex and index buffers void Wreck::createSpine( int sideSteps, int outSteps) { mgBezier outSpline; outSpline.addVertex(mgPoint3( 0.0, 10.0, 9.5), mgPoint3( 0.0, 10.0+10, 9.5-3)); outSpline.addVertex(mgPoint3( 10.0, 40.0, 0.0), mgPoint3( 10.0-10, 40.0, 0.0)); outSpline.addVertex(mgPoint3( 30.0, 10.0, 0.0), mgPoint3( 30.0-10, 10.0, 0.0)); outSpline.addVertex(mgPoint3( 60.0, 10.0, 0.0), mgPoint3( 60.0, 10.0, 0.0)); outSpline.addVertex(mgPoint3(180.0, 10.0, 0.0), mgPoint3(180.0, 10.0, 0.0)); outSpline.addVertex(mgPoint3(180.0, 10.0, 0.0), mgPoint3(180.0-10, 10.0, 0.0)); outSpline.addVertex(mgPoint3(210.0, 30.0, 5.0), mgPoint3(210.0-10, 30.0, 5.0)); outSpline.addVertex(mgPoint3(240.0, 30.0, 5.0), mgPoint3(240.0-10, 30.0, 5.0)); outSpline.addVertex(mgPoint3(235.0, 17.5, 17.0), mgPoint3(235.0, 17.5+5, 17.0-5)); mgBezier sideSpline; double left = 150*PI/180.0; double lx = 10*cos(left); double ly = 10*sin(left); double right = 30*PI/180.0; double rx = 10*cos(right); double ry = 10*sin(right); sideSpline.addVertex(mgPoint3(0.0, 0.0, 0.0), mgPoint3(0.0-1, 0.0+1, 0.0)); sideSpline.addVertex(mgPoint3(lx+2, ly+1, 0.0), mgPoint3(lx+2, ly+1-2, 0.0)); sideSpline.addVertex(mgPoint3(0.0, 10.0, 0.0), mgPoint3(0-2.5, 10, 0.0)); sideSpline.addVertex(mgPoint3(rx-2, ry+1, 0.0), mgPoint3(rx-2, ry+1+2, 0.0)); sideSpline.addVertex(mgPoint3(0.0, 0.0, 0.0), mgPoint3(0.0+1, 0.0+1, 0.0)); for (int i = 0; i < 3; i++) { mgMatrix4 rotate; rotate.rotateZDeg(i*120); buildSurface(sideSpline, 0.1, sideSteps, outSpline, 1.0, outSteps, rotate, false, 0); } }
//-------------------------------------------------------------- // constructor Tower::Tower( const mgOptionsFile& options, BOOL lights) { m_lights = lights; m_shellIndexes = NULL; m_shellVertexes = NULL; m_officeIndexes = NULL; m_officeVertexes = NULL; m_glassIndexes = NULL; // load ball textures. must all be same size. mgString fileName; options.getFileName("tower-shell", options.m_sourceFileName, "tower-body.jpg", fileName); m_shellTexture = mgDisplay->loadTexture(fileName); options.getFileName("tower-glass", options.m_sourceFileName, "tower-glass.jpg", fileName); m_glassTexture = mgDisplay->loadTexture(fileName); mgStringArray fileList; options.getFileName("tower-wall", options.m_sourceFileName, "tower-wall.jpg", fileName); fileList.add(fileName); options.getFileName("tower-light", options.m_sourceFileName, "tower-light.jpg", fileName); fileList.add(fileName); options.getFileName("tower-floor", options.m_sourceFileName, "tower-floor.jpg", fileName); fileList.add(fileName); options.getFileName("tower-wall-dark", options.m_sourceFileName, "tower-wall.jpg", fileName); fileList.add(fileName); options.getFileName("tower-light-dark", options.m_sourceFileName, "tower-light.jpg", fileName); fileList.add(fileName); options.getFileName("tower-floor-dark", options.m_sourceFileName, "tower-floor.jpg", fileName); fileList.add(fileName); options.getFileName("tower-frame", options.m_sourceFileName, "tower-frame.jpg", fileName); fileList.add(fileName); m_officeTextures = mgDisplay->loadTextureArray(fileList); m_floorSpline.addVertex(mgPoint3(-30.0, 0.0, 0.0), mgPoint3(-30.0, 0.0+10, 0.0)); m_floorSpline.addVertex(mgPoint3( 0.0, 10.0, 0.0), mgPoint3( 0.0-30, 10.0, 0.0)); m_floorSpline.addVertex(mgPoint3( 30.0, 0.0, 0.0), mgPoint3( 30.0, 0.0+10, 0.0)); m_floorSpline.addVertex(mgPoint3( 0.0, -10.0, 0.0), mgPoint3( 0.0+30, -10.0, 0.0)); m_floorSpline.addVertex(mgPoint3(-30.0, 0.0, 0.0), mgPoint3(-30.0, 0.0-10, 0.0)); m_floorLen = m_floorSpline.getLength(); m_aptSpline.addVertex(mgPoint3( 0.0, 1.5, 0.0), mgPoint3( 0.0+0, 1.5, 0.0)); m_aptSpline.addVertex(mgPoint3( 3.0, 1.5, 0.0), mgPoint3( 3.0-2.5, 1.5, 0.0)); m_aptSpline.addVertex(mgPoint3( 5.0, 7.5, 0.0), mgPoint3( 5.0, 7.5-2.5, 0.0)); m_aptSpline.addVertex(mgPoint3( 5.0, 7.5, 0.0), mgPoint3( 5.0, 7.5-7.5, 0.0)); m_aptSpline.addVertex(mgPoint3( 35.0, 15.0, 0.0), mgPoint3( 35.0-30, 15.0, 0.0)); m_aptSpline.addVertex(mgPoint3( 65.0, 7.5, 0.0), mgPoint3( 65.0, 7.5+7.5, 0.0)); m_aptSpline.addVertex(mgPoint3( 65.0, 0.0, 0.0), mgPoint3( 65.0, 0.0, 0.0)); m_aptLen = m_aptSpline.getLength(); /* The spline class returns points based on a 'distance' which is a sum of all the segments that define the spline curve, not the actual length of the curve. To get regularly spaced points for windows, we search for the input distances that produce the correct x values (used for height here). The portions of the shape above and below the floors are then generated from the first and last distance point making the floors. */ m_floorDists = new double[APT_STEPS+1]; // find the floor heights for (int i = 0; i <= FLOORS*3; i++) { m_floorDists[15+i] = findSplineX(m_aptSpline, BOTTOM_FLOOR+i, 12, m_aptLen/2); } // fill in the rest of the tower double bottom = m_floorDists[15]; double top = m_floorDists[15+FLOORS*3]; for (int i = 0; i < 15; i++) { m_floorDists[i] = (bottom*i)/15; m_floorDists[16+FLOORS*3+i] = top + (m_aptLen - top)*(i+1)/15.0; } }
//-------------------------------------------------------------- // get avatar orientation under coordinate system void SolarSystem::getCoordBasis( int coordSystem, mgMatrix4& basis) { // get position of moon double angle = (2*PI*m_moonMonth)/360; mgPoint3 moonCenter(MOON_DISTANCE*sin(angle), 0, MOON_DISTANCE*cos(angle)); // get coordinate system based on object mgPoint3 xaxis(1.0, 0.0, 0.0); mgPoint3 yaxis(0.0, 1.0, 0.0); mgPoint3 zaxis(0.0, 0.0, 1.0); switch (coordSystem) { case COORDS_PLANET: // y axis points away from center of planet yaxis = m_coordPosn; yaxis.normalize(); // construct z axis orthonal to y zaxis = yaxis; zaxis.cross(mgPoint3(0.0, 1.0, 0.0)); zaxis.normalize(); // construct x axis xaxis = yaxis; xaxis.cross(zaxis); xaxis.normalize(); break; case COORDS_MOON: // y axis points away from center of moon yaxis = m_coordPosn; yaxis.normalize(); // construct z axis orthonal to y zaxis = yaxis; zaxis.cross(mgPoint3(0.0, 1.0, 0.0)); zaxis.normalize(); // construct x axis xaxis = yaxis; xaxis.cross(zaxis); xaxis.normalize(); break; case COORDS_RING: // y axis points towards center of ring yaxis.x = -m_coordPosn.x; yaxis.z = -m_coordPosn.z; yaxis.y = 0.0; yaxis.normalize(); // x axis is across the ring xaxis.x = 0.0; xaxis.y = 1.0; xaxis.z = 0.0; // construct z axis zaxis = xaxis; zaxis.cross(yaxis); zaxis.normalize(); break; case COORDS_BELT: break; case COORDS_SPACE: // use default axis break; } // apply object surface orientation basis._11 = xaxis.x; basis._21 = xaxis.y; basis._31 = xaxis.z; basis._12 = yaxis.x; basis._22 = yaxis.y; basis._32 = yaxis.z; basis._13 = zaxis.x; basis._23 = zaxis.y; basis._33 = zaxis.z; }
//-------------------------------------------------------------- // initialize application void Landscape::appInit() { MovementApp::appInit(); mgPlatform->setWindowTitle("Landscape, Part 58"); // create the help pane m_help = new HelpUI(m_options); setUI(m_help); // load textures loadTextures(); // load shaders mgVertex::loadShader("litTexture"); mgVertex::loadShader("unlitTexture"); mgVertexTA::loadShader("litTextureArray"); VertexTerrain::loadShader("terrain"); mgVertex::loadShader("water"); // create the sky m_lightDir = mgPoint3(0.0, 0.5, 1.0); m_lightColor = mgPoint3(0.8, 0.8, 0.8); m_lightAmbient = mgPoint3(0.2, 0.2, 0.2); m_fogColor = mgPoint3(0.8, 0.8, 0.8); m_fogMaxDist = 13000.0; m_fogTopHeight = 2000.0; // WATER_LEVEL + 128.0;// m_fogMaxDist; m_fogBotHeight = WATER_LEVEL; m_fogBotInten = 1.0; m_fogTopInten = 0.8; m_sky = new StarrySky(m_options); m_sky->setFogInten(m_fogBotInten, m_fogTopInten); m_sky->setMoonDir(m_lightDir); m_sky->setSunDir(m_lightDir); setDayLight(true); m_maxCount = 0; // number of terrain chunks in use // generate the initial terrain for (int x = 0; x <= 2; x++) { for (int z = 0; z <= 2; z++) { Terrain* chunk = new Terrain( (x-1) * HORIZON_SIZE - HORIZON_SIZE/2, (z-1) * HORIZON_SIZE - HORIZON_SIZE/2, HORIZON_SIZE, HORIZON_SIZE); chunk->createHeightmap(); m_terrain[x][z] = chunk; } } // subdivide terrain around the eye checkTerrainResolution(); m_mapView = false; m_terrainGrid = GRID_TERRAIN; m_mapGrid = GRID_CHUNKS; m_eyeHeight = 1.75; m_eyePt = mgPoint3(7012.1, 358.22, -6287.94); // nice area for initial coordinate double ht = Terrain::heightAtPt(m_eyePt.x, m_eyePt.z); ht = max(ht, WATER_LEVEL); m_eyePt.y = ht + m_eyeHeight; m_eyeRotX = 4.4; m_eyeRotY = 2.84; m_eyeRotZ = 0.0; // init threads m_threadCount = m_options.getInteger("threadCount", 1); m_buildLock = mgOSLock::create(); m_shutdown = false; if (m_threadCount > 0) { m_buildEvent = mgOSEvent::create(); m_buildThreads = mgOSThread::create(m_threadCount, buildThreadProc, mgOSThread::PRIORITY_LOW, this, NULL); } }
//-------------------------------------------------------------------- // render the view void Landscape::appViewDraw() { mgPoint3 renderEyePt(m_eyePt); if (m_mapView) renderEyePt.y = MAPVIEW_HEIGHT; // draw the sky mgDisplay->setFrontAndBack(0.25, 16384); mgMatrix4 identity; m_eyeMatrix.loadIdentity(); if (m_mapView) { m_eyeMatrix.rotateZDeg(m_eyeRotZ); m_eyeMatrix.rotateYDeg(m_eyeRotY); m_eyeMatrix.rotateXDeg(-90); } else { m_eyeMatrix.rotateZDeg(m_eyeRotZ); m_eyeMatrix.rotateYDeg(m_eyeRotY); m_eyeMatrix.rotateXDeg(m_eyeRotX); } mgDisplay->setEyeMatrix(m_eyeMatrix); mgDisplay->setEyePt(mgPoint3(0,0,0)); mgDisplay->setModelTransform(identity); mgDisplay->setCulling(true); m_sky->setFogColor(m_fogColor); m_sky->setFogHeight(m_fogBotHeight - renderEyePt.y, m_fogTopHeight - renderEyePt.y); m_sky->setFogDist(HORIZON_SIZE, m_fogMaxDist); m_sky->render(); // reset state after any changes in sky render mgDisplay->setLightDir(m_lightDir.x, m_lightDir.y, m_lightDir.z); mgDisplay->setMatColor(1.0, 1.0, 1.0); mgDisplay->setLightColor(m_lightColor.x, m_lightColor.y, m_lightColor.z); mgDisplay->setLightAmbient(m_lightAmbient.x, m_lightAmbient.y, m_lightAmbient.z); mgDisplay->setTransparent(false); mgDisplay->setEyeMatrix(m_eyeMatrix); mgDisplay->setEyePt(mgPoint3(0,0,0)); // we use relative coordinates in render if (mgDisplay->getDepthBits() == 32) { mgDisplay->setFrontAndBack(0.25, 65536*4); renderTerrain(); } else if (mgDisplay->getDepthBits() >= 24) { mgDisplay->setFrontAndBack(256, 65536*4); renderTerrain(); mgDisplay->setFrontAndBack(0.25, 256); mgDisplay->clearBuffer(MG_DEPTH_BUFFER); renderTerrain(); } else { mgDisplay->setFrontAndBack(4096, 65536*4); renderTerrain(); mgDisplay->setFrontAndBack(32, 4096); mgDisplay->clearBuffer(MG_DEPTH_BUFFER); renderTerrain(); mgDisplay->setFrontAndBack(0.25, 32); mgDisplay->clearBuffer(MG_DEPTH_BUFFER); renderTerrain(); } }
//-------------------------------------------------------------- // create buffers ready to send to display void Earth::createBuffers() { const int HEAD_STRIPS = 16; const int HEAD_FACES = 32; // three points times two triangles times grid size m_farVertexes = mgVertex::newBuffer(3*2*HEAD_STRIPS * HEAD_FACES); mgVertex tl, tr, bl, br; // create a sphere for (int i = 1; i <= HEAD_STRIPS; i++) { double topAngle = (PI*(i-1))/HEAD_STRIPS; double topRadius = sin(topAngle); double topY = cos(topAngle); double botAngle = (PI*i)/HEAD_STRIPS; double botRadius = sin(botAngle); double botY = cos(botAngle); for (int j = 1; j <= HEAD_FACES; j++) { double leftAngle = (2.0*PI*(j-1))/HEAD_FACES; tl.setPoint(topRadius * cos(leftAngle), topY, topRadius * sin(leftAngle)); bl.setPoint(botRadius * cos(leftAngle), botY, botRadius * sin(leftAngle)); double rightAngle = (2.0*PI*j)/HEAD_FACES; tr.setPoint(topRadius * cos(rightAngle), topY, topRadius * sin(rightAngle)); br.setPoint(botRadius * cos(rightAngle), botY, botRadius * sin(rightAngle)); // set texture coordinates double topTx = (i-1); // /(double)HEAD_STRIPS; double botTx = i; // /(double)HEAD_STRIPS; double leftTx = (j-1); // /(double)HEAD_FACES; double rightTx = j; // /(double)HEAD_FACES; tl.setTexture(leftTx, topTx); tr.setTexture(rightTx, topTx); bl.setTexture(leftTx, botTx); br.setTexture(rightTx, botTx); // use vertexes as normals, since they are from origin mgPoint3 normal; normal = mgPoint3(tl.m_px, tl.m_py, tl.m_pz); normal.normalize(); tl.setNormal(normal.x, normal.y, normal.z); normal = mgPoint3(tr.m_px, tr.m_py, tr.m_pz); normal.normalize(); tr.setNormal(normal.x, normal.y, normal.z); normal = mgPoint3(bl.m_px, bl.m_py, bl.m_pz); normal.normalize(); bl.setNormal(normal.x, normal.y, normal.z); normal = mgPoint3(br.m_px, br.m_py, br.m_pz); normal.normalize(); br.setNormal(normal.x, normal.y, normal.z); tl.addTo(m_farVertexes); tr.addTo(m_farVertexes); bl.addTo(m_farVertexes); bl.addTo(m_farVertexes); tr.addTo(m_farVertexes); br.addTo(m_farVertexes); } } }
//-------------------------------------------------------------- // render the planet void Planet::render( int graphicsWidth, int graphicsHeight, double angle) { // if shader didn't compile, nothing we can do if (m_planetShader == 0) return; double atmos = 20.0; double radius = 1200.0; double eyeDist = m_eyePt.length()/radius; double a = 1.0; if (eyeDist < a) return; // below surface, nothing to do double b = sqrt(eyeDist*eyeDist - a*a); double h = (a*b)/eyeDist; double m = (a*a)/eyeDist; h += atmos/radius; // x axis from planet center towards eye mgPoint3 xaxis(m_eyePt); xaxis.normalize(); // build y axis mgPoint3 yaxis(xaxis); yaxis.cross(mgPoint3(0.0, 1.0, 0.0)); yaxis.normalize(); mgPoint3 zaxis(yaxis); zaxis.cross(xaxis); zaxis.normalize(); mgMatrix4 transform; transform._11 = xaxis.x; transform._12 = xaxis.y; transform._13 = xaxis.z; transform._21 = yaxis.x; transform._22 = yaxis.y; transform._23 = yaxis.z; transform._31 = zaxis.x; transform._32 = zaxis.y; transform._33 = zaxis.z; VertexPlanet tl, tr, bl, br; mgPoint3 pt; transform.mapPt(m, -h, h, pt.x, pt.y, pt.z); tl.setPoint(radius*pt.x, radius*pt.y, radius*pt.z); transform.mapPt(m, h, h, pt.x, pt.y, pt.z); tr.setPoint(radius*pt.x, radius*pt.y, radius*pt.z); transform.mapPt(m, -h, -h, pt.x, pt.y, pt.z); bl.setPoint(radius*pt.x, radius*pt.y, radius*pt.z); transform.mapPt(m, h, -h, pt.x, pt.y, pt.z); br.setPoint(radius*pt.x, radius*pt.y, radius*pt.z); // inverse of world transform mgMatrix4 model; model.rotateYDeg(-angle); mgPoint3 lightDir(1.0, 0.25, 0.0); lightDir.normalize(); mgPoint3 modelLightDir; model.mapPt(lightDir, modelLightDir); transform.multiply(model); mgPoint3 modelEye; transform.mapPt(eyeDist, 0.0, 0.0, modelEye.x, modelEye.y, modelEye.z); transform.mapPt(m, -h, h, pt.x, pt.y, pt.z); tl.setModelPoint(pt.x, pt.y, pt.z); transform.mapPt(m, h, h, pt.x, pt.y, pt.z); tr.setModelPoint(pt.x, pt.y, pt.z); transform.mapPt(m, -h, -h, pt.x, pt.y, pt.z); bl.setModelPoint(pt.x, pt.y, pt.z); transform.mapPt(m, h, -h, pt.x, pt.y, pt.z); br.setModelPoint(pt.x, pt.y, pt.z); mgMatrix4 viewMatrix; viewMatrix.translate(-m_eyePt.x, -m_eyePt.y, -m_eyePt.z); viewMatrix.multiply(m_eyeMatrix); mgMatrix4 worldProjection; createProjection(worldProjection, graphicsWidth, graphicsHeight); mgMatrix4 mvpMatrix(viewMatrix); mvpMatrix.multiply(worldProjection); setupShader(mvpMatrix, modelEye, modelLightDir); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, m_surfaceTexture); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_CUBE_MAP, m_cloudsTexture); glBindVertexArray(m_vertexArray); glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); VertexPlanet data[6]; data[0] = tl; data[1] = tr; data[2] = bl; data[3] = bl; data[4] = tr; data[5] = br; int vertexSize = sizeof(VertexPlanet); int count = 6; glBufferData(GL_ARRAY_BUFFER, vertexSize * count, data, GL_DYNAMIC_DRAW); glDrawArrays(GL_TRIANGLES, 0, count); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); glActiveTexture(GL_TEXTURE0); }
//-------------------------------------------------------------------- // render the view void DontHitMe::appViewDraw() { // draw the sky if (m_sky != NULL) { mgDisplay->setTransparent(true); mgDisplay->setZEnable(false); mgDisplay->setEyeMatrix(m_eyeMatrix); mgDisplay->setEyePt(mgPoint3(0,0,0)); mgMatrix4 identity; mgDisplay->setModelTransform(identity); m_sky->render(); mgDisplay->setTransparent(false); mgDisplay->setZEnable(true); } mgDisplay->setEyeMatrix(m_eyeMatrix); mgDisplay->setEyePt(m_eyePt); mgDisplay->setLightColor(0.8, 0.8, 0.8); // draw the planet if (m_planet != NULL) m_planet->render(); // draw the wreck if (m_wreck != NULL) { mgMatrix4 model; model.translate(0, 0, -120); // center of ship model.rotateYDeg(20); model.rotateZDeg(10); model.translate(215, 0, 30); // near asteroid mgDisplay->setModelTransform(model); m_wreck->render(); } // draw the fallen towers if (m_tower1 != NULL) { mgMatrix4 model; model.rotateYDeg(-80); model.rotateXDeg(10); model.rotateZDeg(-60); model.translate(190, 40, 40); mgDisplay->setModelTransform(model); m_tower1->render(); } if (m_tower2 != NULL) { mgMatrix4 model; model.rotateYDeg(90); model.rotateXDeg(-5); model.rotateZDeg(-105); model.translate(205, -20, 20); mgDisplay->setModelTransform(model); m_tower2->render(); } /* // draw the prickles for (int i = 0; i < m_prickles.length(); i++) { Prickle* prickle = (Prickle*) m_prickles[i]; prickle->render(); } */ if (m_showingIntro) { if (m_intro != NULL) m_intro->render(); } else { // draw the saucer if (m_saucer != NULL) { double saucerScale = 0.5; double ballRadius = 0.5*saucerScale; mgMatrix4 ballModel; ballModel.scale(saucerScale); ballModel.translate(0.0, ballRadius + TUBE_RADIUS, 0.0); // ballModel.rotateZDeg(m_ballRotate); // ballModel.rotateXDeg(m_ballRoll); ballModel.multiply(m_ballMatrix); ballModel.translate(m_ballOrigin); mgDisplay->setModelTransform(ballModel); m_saucer->render(); mgDisplay->setCulling(true); } // draw the track if (m_tube != NULL) { mgDisplay->setTransparent(true); mgMatrix4 tubeModel; mgDisplay->setModelTransform(tubeModel); mgDisplay->setTexture(m_tubeTexture); m_tube->render(); mgDisplay->setTransparent(false); } } }
//-------------------------------------------------------------- // do a step of colonization. return true if added branch BOOL Colonization::colonize() { BOOL active = false; int branchCount = m_branches.length(); // for each leaf, find the closest branch point within the cutoff radius for (int i = m_leaves.length()-1; i >= 0; i--) { Leaf* leaf = getLeaf(i); if (!leaf->m_active) continue; leaf->m_closest = -1; double closestDist = INT_MAX; for (int j = 0; j < branchCount; j++) { Branch* branch = getBranch(j); // calculate distance mgPoint3 dir(leaf->m_pt); dir.subtract(branch->m_pt); double dist = dir.length(); if (dist < MIN_DISTANCE) { leaf->m_active = false; break; } if (dist > MAX_DISTANCE) continue; if (dist < closestDist) { leaf->m_closest = j; closestDist = dist; } } // update growth of closest branch if (leaf->m_closest != -1) { Branch* branch = getBranch(leaf->m_closest); // calculate vector to branch mgPoint3 dir(leaf->m_pt); dir.subtract(branch->m_pt); dir.normalize(); // double dist = dir.length(); // dist = pow(dist, 1.5); // add normalized vector branch->m_growDir.add(dir); branch->m_growCount++; } } // for each branch for (int j = 0; j < branchCount; j++) { Branch* branch = getBranch(j); // if there's growth, add a new branch if (branch->m_growCount != 0) { // normalize the growth direction branch->m_growDir.scale(1.0/branch->m_growCount); branch->m_growDir.normalize(); branch->m_growDir.scale(GROW_DISTANCE); // create a new branch Branch* twig = new Branch(); twig->m_pt = branch->m_pt; twig->m_pt.add(branch->m_growDir); twig->m_parent = j; twig->m_growDir = mgPoint3(0,0,0); twig->m_growCount = 0; twig->m_area = TWIG_AREA; m_branches.add(twig); // reset growth vector on branch branch->m_growDir = mgPoint3(0,0,0); branch->m_growCount = 0; active = true; } } return active; }