bool CAR::LoadPhysics( const PTree & cfg, const std::string & carpath, const MATHVECTOR <float, 3> & initial_position, const QUATERNION <float> & initial_orientation, const bool defaultabs, const bool defaulttcs, const bool damage, ContentManager & content, DynamicsWorld & world, std::ostream & error_output) { std::string carmodel; std::tr1::shared_ptr<MODEL> modelptr; if (!cfg.get("body.mesh", carmodel, error_output)) return false; if (!content.load(carpath, carmodel, modelptr)) return false; btVector3 size = ToBulletVector(modelptr->GetSize()); btVector3 center = ToBulletVector(modelptr->GetCenter()); btVector3 position = ToBulletVector(initial_position); btQuaternion rotation = ToBulletQuaternion(initial_orientation); if (!dynamics.Load(cfg, size, center, position, rotation, damage, world, error_output)) return false; dynamics.SetABS(defaultabs); dynamics.SetTCS(defaulttcs); mz_nominalmax = (GetTireMaxMz(FRONT_LEFT) + GetTireMaxMz(FRONT_RIGHT)) * 0.5; return true; }
bool SPRITE2D::Load( SCENENODE & parent, const std::string & texturepath, const std::string & texturename, ContentManager & content, float draworder) { Unload(parent); assert(!draw.valid()); assert(!node.valid()); TEXTUREINFO texinfo; texinfo.mipmap = false; texinfo.repeatu = false; texinfo.repeatv = false; texinfo.npot = false; std::tr1::shared_ptr<TEXTURE> texture; if (!content.load(texturepath, texturename, texinfo, texture)) return false; node = parent.AddNode(); SCENENODE & noderef = parent.GetNode(node); draw = noderef.GetDrawlist().twodim.insert(DRAWABLE()); DRAWABLE & drawref = GetDrawableFromNode(noderef); drawref.SetDiffuseMap(texture); drawref.SetVertArray(&varray); drawref.SetDrawOrder(draworder); drawref.SetCull(false, false); drawref.SetColor(r,g,b,a); //std::cout << "Sprite draworder: " << draworder << std::endl; return true; }
void PerformanceTesting::Test( const std::string & cardir, const std::string & carname, ContentManager & content, std::ostream & info_output, std::ostream & error_output) { info_output << "Beginning car performance test on " << carname << std::endl; // init track assert(!track); assert(!plane); btVector3 planeNormal(0, 0, 1); btScalar planeConstant = 0; plane = new btStaticPlaneShape(planeNormal, planeConstant); plane->setUserPointer(static_cast<void*>(&surface)); track = new btCollisionObject(); track->setCollisionShape(plane); track->setActivationState(DISABLE_SIMULATION); track->setUserPointer(static_cast<void*>(&surface)); world.addCollisionObject(track); //load the car dynamics std::tr1::shared_ptr<PTree> cfg; content.load(cfg, cardir, carname + ".car"); if (!cfg->size()) { return; } // position is the center of a 2 x 4 x 1 meter box on track surface btVector3 pos(0.0, -2.0, 0.5); btQuaternion rot = btQuaternion::getIdentity(); const std::string tire = ""; const bool damage = false; if (!car.Load(*cfg, cardir, tire, pos, rot, damage, world, content, error_output)) { return; } info_output << "Car dynamics loaded" << std::endl; info_output << carname << " Summary:\n" << "Mass (kg) including driver and fuel: " << 1 / car.GetInvMass() << "\n" << "Center of mass (m): " << car.GetCenterOfMass() << std::endl; std::ostringstream statestream; joeserialize::BinaryOutputSerializer serialize_output(statestream); if (!car.Serialize(serialize_output)) { error_output << "Serialization error" << std::endl; } //else info_output << "Car state: " << statestream.str(); carstate = statestream.str(); TestMaxSpeed(info_output, error_output); TestStoppingDistance(false, info_output, error_output); TestStoppingDistance(true, info_output, error_output); info_output << "Car performance test complete." << std::endl; }
bool FONT::Load( const std::string & fontinfopath, const std::string & texpath, const std::string & texname, ContentManager & content, std::ostream & error_output, bool mipmap) { TEXTUREINFO texinfo; texinfo.mipmap = mipmap; texinfo.repeatu = false; texinfo.repeatv = false; if (!content.load(texpath, texname, texinfo, font_texture)) return false; std::ifstream fontinfo(fontinfopath.c_str()); if (!fontinfo) { error_output << "Can't find font information file: " << fontinfopath << std::endl; return false; } const std::string sizestr("size="); const float sw = font_texture->GetScale() / font_texture->GetW(); const float sh = font_texture->GetScale() / font_texture->GetH(); while (fontinfo) { std::string curstr; fontinfo >> curstr; if (curstr == "char") { unsigned int cur_id(0); if (!Parse("id=", cur_id, fontinfo, fontinfopath, error_output)) return false; CHARINFO & info = charinfo[cur_id]; if (!Parse("x=", info.x, fontinfo, fontinfopath, error_output)) return false; if (!Parse("y=", info.y, fontinfo, fontinfopath, error_output)) return false; if (!Parse("width=", info.width, fontinfo, fontinfopath, error_output)) return false; if (!Parse("height=", info.height, fontinfo, fontinfopath, error_output)) return false; if (!Parse("xoffset=", info.xoffset, fontinfo, fontinfopath, error_output)) return false; if (!Parse("yoffset=", info.yoffset, fontinfo, fontinfopath, error_output)) return false; if (!Parse("xadvance=", info.xadvance, fontinfo, fontinfopath, error_output)) return false; fontinfo >> curstr >> curstr; //don't care info.x *= sw; info.y *= sh; info.width *= sw; info.height *= sh; info.xoffset *= sw; info.yoffset *= sh; info.xadvance *= sw; info.loaded = true; } else if (curstr.compare(0, sizestr.size(), sizestr) == 0)
void PERFORMANCE_TESTING::Test( const std::string & cardir, const std::string & carname, ContentManager & content, std::ostream & info_output, std::ostream & error_output) { info_output << "Beginning car performance test on " << carname << std::endl; //load the car dynamics std::tr1::shared_ptr<PTree> cfg; content.load(cfg, cardir, carname + ".car"); if (!cfg->size()) { return; } btVector3 size(0, 0, 0), center(0, 0, 0), pos(0, 0, 0); // collision shape from wheel data btQuaternion rot = btQuaternion::getIdentity(); bool damage = false; if (!car.Load(*cfg, size, center, pos, rot, damage, world, error_output)) { return; } info_output << "Car dynamics loaded" << std::endl; info_output << carname << " Summary:\n" << "Mass (kg) including driver and fuel: " << 1 / car.GetInvMass() << "\n" << "Center of mass (m): " << car.GetCenterOfMass() << std::endl; std::stringstream statestream; joeserialize::BinaryOutputSerializer serialize_output(statestream); if (!car.Serialize(serialize_output)) { error_output << "Serialization error" << std::endl; } //else info_output << "Car state: " << statestream.str(); carstate = statestream.str(); // fixme info_output << "Car performance test broken - exiting." << std::endl; return; TestMaxSpeed(info_output, error_output); TestStoppingDistance(false, info_output, error_output); TestStoppingDistance(true, info_output, error_output); info_output << "Car performance test complete." << std::endl; }
void ParticleSystem::Load( const std::string & texpath, const std::string & texname, int anisotropy, ContentManager & content) { TextureInfo texinfo; texinfo.anisotropy = anisotropy; content.load(texture, texpath, texname, texinfo); draw = GetDrawlist(node).insert(Drawable()); Drawable & drawref = GetDrawlist(node).get(draw); drawref.SetDrawEnable(false); drawref.SetVertArray(&varrays[cur_varray]); drawref.SetTextures(texture->GetID()); drawref.SetCull(false, false); }
bool CAR::LoadLight( const PTree & cfg, ContentManager & content, std::ostream & error_output) { float radius; std::string radiusstr; MATHVECTOR<float, 3> pos(0), col(0); if (!cfg.get("position", pos, error_output)) return false; if (!cfg.get("color", col, error_output)) return false; if (!cfg.get("radius", radius, error_output)) return false; cfg.get("radius", radiusstr); lights.push_back(LIGHT()); SCENENODE & bodynoderef = topnode.GetNode(bodynode); lights.back().node = bodynoderef.AddNode(); SCENENODE & node = bodynoderef.GetNode(lights.back().node); node.GetTransform().SetTranslation(MATHVECTOR<float,3>(pos[0], pos[1], pos[2])); std::tr1::shared_ptr<MODEL> mesh; if (!content.get("", "cube"+radiusstr, mesh)) { VERTEXARRAY varray; varray.SetToUnitCube(); varray.Scale(radius, radius, radius); content.load("", "cube"+radiusstr, varray, mesh); } models.push_back(mesh); keyed_container <DRAWABLE> & dlist = GetDrawlist(node, OMNI); lights.back().draw = dlist.insert(DRAWABLE()); DRAWABLE & draw = dlist.get(lights.back().draw); draw.SetColor(col[0], col[1], col[2]); draw.SetModel(*mesh); draw.SetCull(true, true); draw.SetDrawEnable(false); return true; }
bool CarGraphics::LoadLight( const PTree & cfg, ContentManager & content, std::ostream & error_output) { float radius; std::string radiusstr; Vec3 pos(0), col(0); if (!cfg.get("position", pos, error_output)) return false; if (!cfg.get("color", col, error_output)) return false; if (!cfg.get("radius", radius, error_output)) return false; cfg.get("radius", radiusstr); lights.push_back(Light()); SceneNode & bodynoderef = topnode.GetNode(bodynode); lights.back().node = bodynoderef.AddNode(); SceneNode & node = bodynoderef.GetNode(lights.back().node); node.GetTransform().SetTranslation(Vec3(pos[0], pos[1], pos[2])); std::shared_ptr<Model> mesh; if (!content.get(mesh, "", "cube" + radiusstr)) { VertexArray varray; varray.SetToUnitCube(); varray.Scale(radius, radius, radius); content.load(mesh, "", "cube" + radiusstr, varray); } models.insert(mesh); keyed_container <Drawable> & dlist = node.GetDrawList().lights_omni; lights.back().draw = dlist.insert(Drawable()); Drawable & draw = dlist.get(lights.back().draw); draw.SetColor(col[0], col[1], col[2]); draw.SetModel(*mesh); draw.SetCull(true); draw.SetDrawEnable(false); return true; }
bool HUD::Init( const std::string & texturepath, ContentManager & content, FONT & lcdfont, FONT & sansfont, FONT & sansfont_noshader, float displaywidth, float displayheight, bool debugon, std::ostream & error_output) { const float opacity = 0.8; const float screenhwratio = displayheight / displaywidth; const float barheight = 64.0 / displayheight; const float barwidth = 256.0 / displaywidth; TEXTUREINFO texinfo; texinfo.mipmap = false; texinfo.repeatu = false; texinfo.repeatv = false; float timerbox_lowery = 0; { timernode = hudroot.AddNode(); SCENENODE & timernoderef = hudroot.GetNode(timernode); float timerboxdimx = 96.0 / displaywidth; float timerboxdimy = 64.0 / displayheight; timerboxdraw = AddDrawable(timernoderef); DRAWABLE & timerboxdrawref = GetDrawable(timernoderef, timerboxdraw); TEXTUREINFO timerboxtexinfo; timerboxtexinfo.mipmap = false; timerboxtexinfo.repeatu = true; timerboxtexinfo.repeatv = false; std::tr1::shared_ptr<TEXTURE> timerboxtex; if (!content.load(texturepath, "timerbox.png", timerboxtexinfo, timerboxtex)) return false; float totalsizex = timerboxdimx * 6.05; float totalsizey = timerboxdimy * 2.0; float x = totalsizex * 0.5 - timerboxdimx * 0.65; float y = totalsizey * 0.5 - timerboxdimy * 0.25; float w = totalsizex - timerboxdimx * 2; float h = totalsizey - timerboxdimy * 2; timerboxverts.SetTo2DBox(x, y, w, h, timerboxdimx, timerboxdimy); timerbox_lowery = y + timerboxdimy * 0.5; timerboxdrawref.SetDiffuseMap(timerboxtex); timerboxdrawref.SetVertArray(&timerboxverts); timerboxdrawref.SetCull(false, false); timerboxdrawref.SetColor(1, 1, 1, opacity); timerboxdrawref.SetDrawOrder(0.1); float fontscaley = timerboxdimy * 0.4; float fontscalex = fontscaley * screenhwratio; float startx = timerboxdimx * 0.45 - timerboxdimx * 0.15; float xinc = timerboxdimx * 1.5; laptime_label.Init(timernoderef, sansfont, "Lap time:", startx, timerboxdimy*0.9-timerboxdimy*0.3, fontscalex, fontscaley); laptime_label.SetDrawOrder(timernoderef, 0.2); lastlaptime_label.Init(timernoderef, sansfont, "Last lap:", startx+xinc, timerboxdimy*.9-timerboxdimy*0.3, fontscalex, fontscaley); lastlaptime_label.SetDrawOrder(timernoderef, 0.2); bestlaptime_label.Init(timernoderef, sansfont, "Best lap:", startx+xinc*2.0, timerboxdimy*.9-timerboxdimy*0.3, fontscalex, fontscaley); bestlaptime_label.SetDrawOrder(timernoderef, 0.2); laptime.Init(timernoderef, lcdfont, "", startx, timerboxdimy*1.2-timerboxdimy*0.3, fontscalex, fontscaley); laptime.SetDrawOrder(timernoderef, 0.2); lastlaptime.Init(timernoderef, lcdfont, "", startx+xinc, timerboxdimy*1.2-timerboxdimy*0.3, fontscalex, fontscaley); lastlaptime.SetDrawOrder(timernoderef, 0.2); bestlaptime.Init(timernoderef, lcdfont, "", startx+xinc*2.0, timerboxdimy*1.2-timerboxdimy*0.3, fontscalex, fontscaley); bestlaptime.SetDrawOrder(timernoderef, 0.2); } { float fontscaley = barheight * 0.5; float fontscalex = screenhwratio * fontscaley; float x = fontscalex * 0.25; float y = timerbox_lowery + fontscaley; driftscoreindicator.Init(hudroot, sansfont, "", x, y, fontscalex, fontscaley); driftscoreindicator.SetDrawOrder(hudroot, 0.2); } { float fontscaley = barheight * 0.5; float fontscalex = screenhwratio * fontscaley; float x = fontscalex * 0.25; float y = timerbox_lowery + fontscaley * 2; lapindicator.Init(hudroot, sansfont, "", x, y, fontscalex, fontscaley); lapindicator.SetDrawOrder(hudroot, 0.2); } { float fontscaley = barheight * 0.5; float fontscalex = screenhwratio * fontscaley; float x = fontscalex * 0.25; float y = timerbox_lowery + fontscaley * 3; placeindicator.Init(hudroot, sansfont, "", x, y, fontscalex, fontscaley); placeindicator.SetDrawOrder(hudroot, 0.2); } { float fontscaley = barheight * 0.5; float fontscalex = screenhwratio * fontscaley; float x = 0.5; float y = 0.5; raceprompt.Init(hudroot, sansfont, "", x, y, fontscalex, fontscaley); raceprompt.SetDrawOrder(hudroot, 1.0); raceprompt.SetColor(hudroot, 1, 0, 0); } { float fontscaley = 0.02; float fontscalex = screenhwratio * fontscaley; debugnode = hudroot.AddNode(); SCENENODE & debugnoderef = hudroot.GetNode(debugnode); debugtextdraw1 = SetupText(debugnoderef, sansfont, debugtext1, "", 0.01, fontscaley, fontscalex, fontscaley, 1, 1, 1, 10); debugtextdraw2 = SetupText(debugnoderef, sansfont, debugtext2, "", 0.25, fontscaley, fontscalex, fontscaley, 1, 1, 1, 10); debugtextdraw3 = SetupText(debugnoderef, sansfont, debugtext3, "", 0.5, fontscaley, fontscalex, fontscaley, 1, 1, 1, 10); debugtextdraw4 = SetupText(debugnoderef, sansfont, debugtext4, "", 0.75, fontscaley, fontscalex, fontscaley, 1, 1, 1, 10); } #ifndef GAUGES std::tr1::shared_ptr<TEXTURE> bartex, progbartex; if (!content.load(texturepath, "hudbox.png", texinfo, bartex)) return false; if (!content.load(texturepath, "progressbar.png", texinfo, progbartex)) return false; rpmbar = AddDrawable(hudroot); rpmredbar = AddDrawable(hudroot); rpmbox = AddDrawable(hudroot); DRAWABLE & rpmboxref = GetDrawable(hudroot, rpmbox); rpmboxref.SetDiffuseMap(progbartex); rpmboxref.SetVertArray(&rpmboxverts); rpmboxref.SetDrawOrder(2); rpmboxref.SetCull(false, false); rpmboxref.SetColor(0.3, 0.3, 0.3, 0.4); DRAWABLE & rpmbarref = GetDrawable(hudroot, rpmbar); rpmbarref.SetDiffuseMap(progbartex); rpmbarref.SetVertArray(&rpmbarverts); rpmbarref.SetDrawOrder(3); rpmbarref.SetCull(false, false); rpmbarref.SetColor(1.0, 1.0, 1.0, 0.7); DRAWABLE & rpmredbarref = GetDrawable(hudroot, rpmredbar); rpmredbarref.SetDiffuseMap(progbartex); rpmredbarref.SetVertArray(&rpmredbarverts); rpmredbarref.SetColor(1.0, 0.2, 0.2, 0.7); rpmredbarref.SetDrawOrder(3); rpmredbarref.SetCull(false, false); //lower left bar bars.push_back(HUDBAR()); bars.back().Set(hudroot, bartex, 0.0 + barwidth * 0.5, 1.0-barheight*0.5, barwidth, barheight, opacity, false); //lower right bar bars.push_back(HUDBAR()); bars.back().Set(hudroot, bartex, 1.0 - barwidth * 0.175, 1.0-barheight*0.5, barwidth, barheight, opacity, false); { float fontscaley = barheight * 0.5; float fontscalex = screenhwratio * fontscaley; float y = 1.0 - fontscaley * 0.5; float x0 = screenhwratio * 0.02; float x1 = 1.0 - screenhwratio * 0.02; geartextdraw = SetupText(hudroot, lcdfont, geartext, "N", x0, y, fontscalex, fontscaley, 1, 1, 1, 4); mphtextdraw = SetupText(hudroot, lcdfont, mphtext, "0", x1, y, fontscalex, fontscaley, 1, 1, 1, 4); } { float fontscaley = barheight * 0.25; float fontscalex = screenhwratio * fontscaley; float x0 = 1 - barwidth * 0.6; float x1 = 1 - barwidth * 0.7; float y0 = 1 - fontscaley * 1.25; float y1 = 1 - fontscaley * 0.5; abs.Init(hudroot, sansfont, "ABS", x0, y0, fontscalex, fontscaley); abs.SetDrawOrder(hudroot, 4); abs.SetColor(hudroot, 0, 1, 0); tcs.Init(hudroot, sansfont, "TCS", x0, y1, fontscalex, fontscaley); tcs.SetDrawOrder(hudroot, 4); tcs.SetColor(hudroot, 1, 0.77, 0.23); gas.Init(hudroot, sansfont, "GAS", x1, y0, fontscalex, fontscaley); gas.SetDrawOrder(hudroot, 4); gas.SetColor(hudroot, 1, 0, 0); nos.Init(hudroot, sansfont, "NOS", x1, y1, fontscalex, fontscaley); nos.SetDrawOrder(hudroot, 4); nos.SetColor(hudroot, 0, 1, 0); } #else { FONT & gaugefont = sansfont_noshader; // gauge texture char white[] = {255, 255, 255, 255}; TEXTUREINFO tinfo; tinfo.data = white; tinfo.width = 1; tinfo.height = 1; tinfo.bytespp = 4; tinfo.mipmap = false; std::tr1::shared_ptr<TEXTURE> texture; content.load("", "white1x1", tinfo, texture); float r = 0.12; float x0 = 0.15; float x1 = 0.85; float y0 = 0.85; float h0 = r * 0.25; float w0 = screenhwratio * h0; float angle_min = 315.0 / 180.0 * M_PI; float angle_max = 45.0 / 180.0 * M_PI; rpmgauge.Set(hudroot, texture, gaugefont, screenhwratio, x0, y0, r, angle_min, angle_max, 0, maxrpm * 0.001, 1); speedgauge.Set(hudroot, texture, gaugefont, screenhwratio, x1, y0, r, angle_min, angle_max, 0, maxspeed * speedscale, 10); float w = w0; float h = h0; float x = x0 - gaugefont.GetWidth("rpm") * w * 0.5; float y = y0 - r * 0.5; DRAWABLE & rpmd = GetDrawable(hudroot, AddDrawable(hudroot)); rpmlabel.Set(rpmd, gaugefont, "rpm", x, y, w, h, 1, 1, 1); w = w0 * 0.65; h = h0 * 0.65; x = x0 - gaugefont.GetWidth("x1000") * w * 0.5; y = y0 - r * 0.5 + h; DRAWABLE & x1000d = GetDrawable(hudroot, AddDrawable(hudroot)); rpmxlabel.Set(x1000d, gaugefont, "x1000", x, y, w, h, 1, 1, 1); w = w0; h = h0; x = x1 - gaugefont.GetWidth("kph") * w * 0.5; y = y0 - r * 0.5; DRAWABLE & spdd = GetDrawable(hudroot, AddDrawable(hudroot)); speedlabel.Set(spdd, gaugefont, "kph", x, y, w, h, 1, 1, 1); w = w0 * 2; h = h0 * 2; x = x0 - w * 0.25; y = y0 + r * 0.64; geartextdraw = SetupText(hudroot, gaugefont, geartext, "N", x, y, w, h, 1, 1, 1); w = w0 * 1.5; h = h0 * 1.5; x = x1 - w * 0.3; y = y0 + r * 0.68; mphtextdraw = SetupText(hudroot, gaugefont, mphtext, "0", x, y, w, h, 1, 1, 1); } { float fontscaley = barheight * 0.25; float fontscalex = screenhwratio * fontscaley; float x0 = 1 - barwidth * 0.6; float x1 = 1 - barwidth * 0.7; float y0 = 1 - fontscaley * 1.25; float y1 = 1 - fontscaley * 0.5; abs.Init(hudroot, sansfont, "ABS", x0, y0, fontscalex, fontscaley); abs.SetDrawOrder(hudroot, 4); abs.SetColor(hudroot, 0, 1, 0); tcs.Init(hudroot, sansfont, "TCS", x0, y1, fontscalex, fontscaley); tcs.SetDrawOrder(hudroot, 4); tcs.SetColor(hudroot, 1, 0.77, 0.23); gas.Init(hudroot, sansfont, "GAS", x1, y0, fontscalex, fontscaley); gas.SetDrawOrder(hudroot, 4); gas.SetColor(hudroot, 1, 0, 0); nos.Init(hudroot, sansfont, "NOS", x1, y1, fontscalex, fontscaley); nos.SetDrawOrder(hudroot, 4); nos.SetColor(hudroot, 0, 1, 0); } #endif SetVisible(false); debug_hud_info = debugon; return true; }
bool CarSound::Load( const std::string & carpath, const std::string & carname, Sound & sound, ContentManager & content, std::ostream & error_output) { assert(!psound); // check for sound specification file std::string path_aud = carpath + "/" + carname + ".aud"; std::ifstream file_aud(path_aud.c_str()); if (file_aud.good()) { PTree aud; read_ini(file_aud, aud); enginesounds.reserve(aud.size()); for (const auto & i : aud) { const PTree & audi = i.second; std::string filename; std::shared_ptr<SoundBuffer> soundptr; if (!audi.get("filename", filename, error_output)) return false; enginesounds.push_back(EngineSoundInfo()); EngineSoundInfo & info = enginesounds.back(); if (!audi.get("MinimumRPM", info.minrpm, error_output)) return false; if (!audi.get("MaximumRPM", info.maxrpm, error_output)) return false; if (!audi.get("NaturalRPM", info.naturalrpm, error_output)) return false; bool powersetting; if (!audi.get("power", powersetting, error_output)) return false; if (powersetting) info.power = EngineSoundInfo::POWERON; else if (!powersetting) info.power = EngineSoundInfo::POWEROFF; else info.power = EngineSoundInfo::BOTH; info.sound_source = sound.AddSource(soundptr, 0, true, true); sound.SetSourceGain(info.sound_source, 0); } // set blend start and end locations -- requires multiple passes std::map <EngineSoundInfo *, EngineSoundInfo *> temporary_to_actual_map; std::list <EngineSoundInfo> poweron_sounds, poweroff_sounds; for (auto & info : enginesounds) { if (info.power == EngineSoundInfo::POWERON) { poweron_sounds.push_back(info); temporary_to_actual_map[&poweron_sounds.back()] = &info; } else if (info.power == EngineSoundInfo::POWEROFF) { poweroff_sounds.push_back(info); temporary_to_actual_map[&poweroff_sounds.back()] = &info; } } poweron_sounds.sort(); poweroff_sounds.sort(); // we only support 2 overlapping sounds at once each for poweron and poweroff; this // algorithm fails for other cases (undefined behavior) std::list <EngineSoundInfo> * cursounds = &poweron_sounds; for (int n = 0; n < 2; n++) { if (n == 1) cursounds = &poweroff_sounds; for (auto i = (*cursounds).begin(); i != (*cursounds).end(); ++i) { // set start blend if (i == (*cursounds).begin()) i->fullgainrpmstart = i->minrpm; // set end blend auto inext = i; inext++; if (inext == (*cursounds).end()) i->fullgainrpmend = i->maxrpm; else { i->fullgainrpmend = inext->minrpm; inext->fullgainrpmstart = i->maxrpm; } } // now assign back to the actual infos for (auto & info : *cursounds) { assert(temporary_to_actual_map.find(&info) != temporary_to_actual_map.end()); *temporary_to_actual_map[&info] = info; } } } else { std::shared_ptr<SoundBuffer> soundptr; content.load(soundptr, carpath, "engine"); enginesounds.push_back(EngineSoundInfo()); enginesounds.back().sound_source = sound.AddSource(soundptr, 0, true, true); } //set up tire squeal sounds for (int i = 0; i < 4; ++i) { std::shared_ptr<SoundBuffer> soundptr; content.load(soundptr, carpath, "tire_squeal"); tiresqueal[i] = sound.AddSource(soundptr, i * 0.25, true, true); } //set up tire gravel sounds for (int i = 0; i < 4; ++i) { std::shared_ptr<SoundBuffer> soundptr; content.load(soundptr, carpath, "gravel"); gravelsound[i] = sound.AddSource(soundptr, i * 0.25, true, true); } //set up tire grass sounds for (int i = 0; i < 4; ++i) { std::shared_ptr<SoundBuffer> soundptr; content.load(soundptr, carpath, "grass"); grasssound[i] = sound.AddSource(soundptr, i * 0.25, true, true); } //set up bump sounds for (int i = 0; i < 4; ++i) { std::shared_ptr<SoundBuffer> soundptr; if (i >= 2) { content.load(soundptr, carpath, "bump_rear"); } else { content.load(soundptr, carpath, "bump_front"); } tirebump[i] = sound.AddSource(soundptr, 0, true, false); } //set up crash sound { std::shared_ptr<SoundBuffer> soundptr; content.load(soundptr, carpath, "crash"); crashsound = sound.AddSource(soundptr, 0, true, false); } //set up gear sound { std::shared_ptr<SoundBuffer> soundptr; content.load(soundptr, carpath, "gear"); gearsound = sound.AddSource(soundptr, 0, true, false); } //set up brake sound { std::shared_ptr<SoundBuffer> soundptr; content.load(soundptr, carpath, "brake"); brakesound = sound.AddSource(soundptr, 0, true, false); } //set up handbrake sound { std::shared_ptr<SoundBuffer> soundptr; content.load(soundptr, carpath, "handbrake"); handbrakesound = sound.AddSource(soundptr, 0, true, false); } { std::shared_ptr<SoundBuffer> soundptr; content.load(soundptr, carpath, "wind"); roadnoise = sound.AddSource(soundptr, 0, true, true); } psound = &sound; return true; }
bool GuiPage::Load( const std::string & path, const std::string & texpath, const float hwratio, const GuiLanguage & lang, const Font & font, const StrSignalMap & vsignalmap, const StrVecSlotMap & vnactionmap, const StrSlotMap & vactionmap, IntSlotMap nactionmap, SlotMap actionmap, ContentManager & content, std::ostream & error_output) { Clear(); Config pagefile; if (!pagefile.load(path)) { error_output << "Couldn't find GUI page file: " << path << std::endl; return false; } if (!pagefile.get("", "name", name, error_output)) return false; //error_output << "Loading " << path << std::endl; // load widgets and controls active_control = 0; std::map<std::string, GuiWidget*> widgetmap; // labels, images, sliders std::map<std::string, GuiWidgetList*> widgetlistmap; // labels, images lists std::vector<Config::const_iterator> controlit; // control iterator cache std::vector<Config::const_iterator> controlnit; // control list iterator cache std::vector<GuiControlList*> controllists; // control list cache for (Config::const_iterator section = pagefile.begin(); section != pagefile.end(); ++section) { if (section->first.empty()) continue; Rect r = LoadRect(pagefile, section, hwratio); float x0 = r.x - r.w * 0.5; float y0 = r.y - r.h * 0.5; float x1 = r.x + r.w * 0.5; float y1 = r.y + r.h * 0.5; GuiWidget * widget = 0; // load widget(list) std::string value; if (pagefile.get(section, "text", value)) { std::string alignstr; float fontsize = 0.03; pagefile.get(section, "fontsize", fontsize); pagefile.get(section, "align", alignstr); int align = 0; if (alignstr == "right") align = 1; else if (alignstr == "left") align = -1; float scaley = fontsize; float scalex = fontsize * hwratio; GuiLabelList * widget_list = 0; if (LoadList(pagefile, section, x0, y0, x1, y1, hwratio, widget_list)) { // connect with the value list StrVecSlotMap::const_iterator vni = vnactionmap.find(value); if (vni != vnactionmap.end()) { StrSignalMap::const_iterator vsi = vsignalmap.find(value + ".update"); if (vsi != vsignalmap.end()) { widget_list->update_list.connect(*vsi->second); vni->second->connect(widget_list->get_values); } } // init drawable widget_list->SetupDrawable(node, font, align, scalex, scaley, r.z); widgetlistmap[section->first] = widget_list; widget = widget_list; } else { // none is reserved for empty text string if (value == "none") value.clear(); else value = lang(value); GuiLabel * new_widget = new GuiLabel(); new_widget->SetupDrawable( node, font, align, scalex, scaley, r.x, r.y, r.w, r.h, r.z); ConnectAction(value, vsignalmap, new_widget->set_value); std::string name; if (pagefile.get(section, "name", name)) labels[name] = new_widget; widgetmap[section->first] = new_widget; widget = new_widget; } } else if (pagefile.get(section, "image", value)) { std::string slider, ext, path = texpath; pagefile.get(section, "path", path); pagefile.get(section, "ext", ext); GuiImageList * widget_list = 0; if (LoadList(pagefile, section, x0, y0, x1, y1, hwratio, widget_list)) { // init drawable widget_list->SetupDrawable(node, content, path, ext, r.z); // connect with the value list StrVecSlotMap::const_iterator vni = vnactionmap.find(value); if (vni != vnactionmap.end()) { StrSignalMap::const_iterator vsi = vsignalmap.find(value + ".update"); if (vsi != vsignalmap.end()) { widget_list->update_list.connect(*vsi->second); vni->second->connect(widget_list->get_values); } } else { // special case of list containing the same image? widget_list->SetImage(value); } widgetlistmap[section->first] = widget_list; widget = widget_list; } else if (pagefile.get(section, "slider", slider)) { bool fill = false; pagefile.get(section, "fill", fill); TextureInfo texinfo; texinfo.mipmap = false; texinfo.repeatu = false; texinfo.repeatv = false; std::tr1::shared_ptr<Texture> tex; content.load(tex, texpath, value, texinfo); float radius = 0.0; if (pagefile.get(section, "radius", radius)) { float start_angle(0), end_angle(2 * M_PI); pagefile.get(section, "start-angle", start_angle); pagefile.get(section, "end-angle", end_angle); GuiRadialSlider * new_widget = new GuiRadialSlider(); new_widget->SetupDrawable( node, tex, r.x, r.y, r.w, r.h, r.z, start_angle, end_angle, radius, hwratio, fill, error_output); ConnectAction(slider, vsignalmap, new_widget->set_value); widget = new_widget; } else { GuiSlider * new_widget = new GuiSlider(); new_widget->SetupDrawable( node, tex, r.x, r.y, r.w, r.h, r.z, fill, error_output); ConnectAction(slider, vsignalmap, new_widget->set_value); widget = new_widget; } widgetmap[section->first] = widget; } else { GuiImage * new_widget = new GuiImage(); new_widget->SetupDrawable( node, content, path, ext, r.x, r.y, r.w, r.h, r.z); ConnectAction(value, vsignalmap, new_widget->set_image); widgetmap[section->first] = new_widget; widget = new_widget; } } // set widget properties (connect property slots) if (widget) { std::string val; if (pagefile.get(section, "visible", val)) ConnectAction(val, vsignalmap, widget->set_visible); if (pagefile.get(section, "opacity", val)) ConnectAction(val, vsignalmap, widget->set_opacity); if (pagefile.get(section, "color", val)) ConnectAction(val, vsignalmap, widget->set_color); if (pagefile.get(section, "hue", val)) ConnectAction(val, vsignalmap, widget->set_hue); if (pagefile.get(section, "sat", val)) ConnectAction(val, vsignalmap, widget->set_sat); if (pagefile.get(section, "val", val)) ConnectAction(val, vsignalmap, widget->set_val); widgets.push_back(widget); } // load controls bool focus; if (pagefile.get(section, "focus", focus)) { GuiControl * control = 0; GuiControlList * control_list = 0; if (LoadList(pagefile, section, x0, y0, x1, y1, hwratio, control_list)) { // register control list scroll actions actionmap[section->first + ".scrollf"] = &control_list->scroll_fwd; actionmap[section->first + ".scrollr"] = &control_list->scroll_rev; // connect with item list if (pagefile.get(section, "list", value)) { StrSignalMap::const_iterator vsu = vsignalmap.find(value + ".update"); StrSignalMap::const_iterator vsn = vsignalmap.find(value + ".nth"); if (vsu != vsignalmap.end() && vsn != vsignalmap.end()) { control_list->update_list.connect(*vsu->second); control_list->set_nth.connect(*vsn->second); } else { error_output << value << " is not a list." << std::endl; } } control = control_list; controlnit.push_back(section); controllists.push_back(control_list); } else { control = new GuiControl(); controlit.push_back(section); controls.push_back(control); } control->SetRect(x0, y0, x1, y1); if (focus) active_control = control; } } // load control actions (connect control signals) // parse control event actions with values(arguments) typedef std::pair<std::string, Slot2<int, const std::string &>*> ActionValn; typedef std::pair<std::string, Slot1<const std::string &>*> ActionVal; std::set<ActionValn> action_valn_set; std::set<ActionVal> action_val_set; std::string actionstr; for (size_t i = 0; i < controlit.size(); ++i) { for (size_t j = 0; j < GuiControl::signal_names.size(); ++j) { if (pagefile.get(controlit[i], GuiControl::signal_names[j], actionstr)) ParseActions(actionstr, vactionmap, widgetmap, widgetlistmap, action_val_set, action_valn_set); } } for (size_t i = 0; i < controlnit.size(); ++i) { for (size_t j = 0; j < GuiControl::signal_names.size(); ++j) { if (pagefile.get(controlnit[i], GuiControl::signal_names[j], actionstr)) ParseActions(actionstr, vactionmap, widgetmap, widgetlistmap, action_val_set, action_valn_set); } } // parse page event actions with values if (pagefile.get("", "onfocus", actionstr)) ParseActions(actionstr, vactionmap, widgetmap, widgetlistmap, action_val_set, action_valn_set); if (pagefile.get("", "oncancel", actionstr)) ParseActions(actionstr, vactionmap, widgetmap, widgetlistmap, action_val_set, action_valn_set); // register controls, so that they can be activated by control events control_set.reserve(controlit.size() + controlnit.size()); RegisterControls(controlit, controls, this, control_set, actionmap); RegisterControls(controlnit, controllists, this, control_set, actionmap); // register action calls with a parameter, so that they can be signaled by controls RegisterActions(lang, action_val_set, action_set, actionmap); RegisterActions(lang, action_valn_set, action_setn, nactionmap); // connect control signals with their actions for (size_t i = 0; i < controlit.size(); ++i) { for (size_t j = 0; j < GuiControl::EVENTNUM; ++j) { if (pagefile.get(controlit[i], GuiControl::signal_names[j], actionstr)) ConnectActions(actionstr, actionmap, controls[i]->m_signal[j]); } for (size_t j = 0; j < GuiControl::EVENTVNUM; ++j) { if (pagefile.get(controlit[i], GuiControl::signal_names[GuiControl::EVENTNUM + j], actionstr)) ConnectActions(actionstr, vactionmap, controls[i]->m_signalv[j]); } } for (size_t i = 0; i < controlnit.size(); ++i) { for (size_t j = 0; j < GuiControl::EVENTNUM; ++j) { if (pagefile.get(controlnit[i], GuiControl::signal_names[j], actionstr)) { ConnectActions(actionstr, actionmap, controllists[i]->m_signal[j]); ConnectActions(actionstr, nactionmap, controllists[i]->m_signaln[j]); } } } // connect page event signals with their actions if (pagefile.get("", "onfocus", actionstr)) ConnectActions(actionstr, actionmap, onfocus); if (pagefile.get("", "oncancel", actionstr)) ConnectActions(actionstr, actionmap, oncancel); controls.insert(controls.end(), controllists.begin(), controllists.end()); // set active control if (!active_control && !controls.empty()) active_control = controls[0]; // enable active control if (active_control) active_control->Signal(GuiControl::FOCUS); // set default control default_control = active_control; return true; }
bool TRACKMAP::BuildMap( const std::list <ROADSTRIP> & roads, int w, int h, const std::string & trackname, const std::string & texturepath, ContentManager & content, std::ostream & error_output) { Unload(); int outsizex = MAP_WIDTH; int outsizey = MAP_HEIGHT; int bpp = 32; // SDL interprets each pixel as a 32-bit number, so our masks must depend // on the endianness (byte order) of the machine Uint32 rmask, gmask, bmask, amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, outsizex, outsizey, bpp, rmask, gmask, bmask, amask); //find the map width and height mapsize.Set(0,0); map_w_min = FLT_MAX; map_w_max = FLT_MIN; map_h_min = FLT_MAX; map_h_max = FLT_MIN; for (list <ROADSTRIP>::const_iterator road = roads.begin(); road != roads.end(); road++) { for (vector<ROADPATCH>::const_iterator curp = road->GetPatches().begin(); curp != road->GetPatches().end(); curp++) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { MATHVECTOR <float, 3> p = curp->GetPatch()[i+j*4]; if (p[0] < map_w_min) { map_w_min = p[0]; } if (p[0] > map_w_max) { map_w_max = p[0]; } if (p[2] < map_h_min) { map_h_min = p[2]; } if (p[2] > map_h_max) { map_h_max = p[2]; } } } } } mapsize[0] = map_w_max - map_w_min; mapsize[1] = map_h_max - map_h_min; //determine the scaling factor //we will leave a 1 pixel border float scale_w = (outsizex-2) / mapsize[0]; float scale_h = (outsizey-2) / mapsize[1]; scale = (scale_w < scale_h)?scale_w:scale_h; boxRGBA(surface, 0, 0, outsizex-1, outsizey-1, 0, 0, 0, 0); for (list <ROADSTRIP>::const_iterator road = roads.begin(); road != roads.end(); road++) { for (vector<ROADPATCH>::const_iterator curp = road->GetPatches().begin(); curp != road->GetPatches().end(); curp++) { Sint16 x[4], y[4]; const BEZIER & b(curp->GetPatch()); MATHVECTOR <float, 3> back_l = b.GetBL(); MATHVECTOR <float, 3> back_r = b.GetBR(); MATHVECTOR <float, 3> front_l = b.GetFL(); MATHVECTOR <float, 3> front_r = b.GetFR(); x[0] = int((back_l[0] - map_w_min) * scale) + 1; y[0] = int((back_l[2] - map_h_min) * scale) + 1; x[1] = int((front_l[0] - map_w_min) * scale) + 1; y[1] = int((front_l[2] - map_h_min) * scale) + 1; x[2] = int((front_r[0] - map_w_min) * scale) + 1; y[2] = int((front_r[2] - map_h_min) * scale) + 1; x[3] = int((back_r[0] - map_w_min) * scale) + 1; y[3] = int((back_r[2] - map_h_min) * scale) + 1; filledPolygonRGBA(surface, x, y, 4, 255, 255, 255, 255); //aapolygonRGBA(surface, x, y, 4, 255, 255, 255, 255); // draw artifacts with SDL2 } } //draw a black border around the track Uint32* rawpixels = (Uint32*)surface->pixels; Uint32 rgbmask = rmask | gmask | bmask; for (int x = 0; x < outsizex; x++) { for (int y = 0; y < outsizey; y++) { //if this pixel is black if (rawpixels[outsizex * y + x] == 0) { //if the pixel above this one is non-black if ((y > 0) && ((rawpixels[outsizex * (y-1) + x] & rgbmask) > 0)) { //set this pixel to non-transparent rawpixels[outsizex * y + x] |= amask; } //if the pixel left of this one is non-black if ((x > 0) && ((rawpixels[outsizex * y + x - 1] & rgbmask) > 0)) { //set this pixel to non-transparent rawpixels[outsizex * y + x] |= amask; } //if the pixel right of this one is non-black if ((x < (outsizex - 1)) && ((rawpixels[outsizex * y + x + 1] & rgbmask) > 0)) { //set this pixel to non-transparent rawpixels[outsizex * y + x] |= amask; } //if the pixel below this one is non-black if ((y < (outsizey - 1)) && ((rawpixels[outsizex * (y+1) + x] & rgbmask) > 0)) { //set this pixel to non-transparent rawpixels[outsizex * y + x] |= amask; } } } } TEXTUREINFO texinfo; texinfo.data = (char*)surface->pixels; texinfo.width = surface->w; texinfo.height = surface->h; texinfo.bytespp = surface->format->BitsPerPixel / 8; texinfo.repeatu = false; texinfo.repeatv = false; std::tr1::shared_ptr<TEXTURE> track_map; content.load(track_map, "", trackname, texinfo); SDL_FreeSurface(surface); //std::cout << "Loading track map dots" << std::endl; TEXTUREINFO dotinfo; content.load(cardot0, texturepath, "cardot0.png", dotinfo); content.load(cardot1, texturepath, "cardot1.png", dotinfo); content.load(cardot0_focused, texturepath, "cardot0_focused.png", dotinfo); content.load(cardot1_focused, texturepath, "cardot1_focused.png", dotinfo); // calculate map position, size screen[0] = (float)w; screen[1] = (float)h; position[0] = 1.0 - MAP_WIDTH / screen[0]; position[1] = 0.12; size[0] = MAP_WIDTH / screen[0]; size[1] = MAP_HEIGHT / screen[1]; dot_size[0] = cardot0->GetW() / 2.0 / screen[0]; dot_size[1] = cardot0->GetH() / 2.0 / screen[1]; mapverts.SetToBillboard(position[0], position[1], position[0]+size[0], position[1]+size[1]); mapdraw = mapnode.GetDrawlist().twodim.insert(DRAWABLE()); DRAWABLE & mapdrawref = mapnode.GetDrawlist().twodim.get(mapdraw); mapdrawref.SetDiffuseMap(track_map); mapdrawref.SetVertArray(&mapverts); mapdrawref.SetCull(false, false); mapdrawref.SetColor(1,1,1,0.7); mapdrawref.SetDrawOrder(0); return true; }
bool CarGraphics::Load( const PTree & cfg, const std::string & carpath, const std::string & /*carname*/, const std::string & carwheel, const std::string & carpaint, const Vec3 & carcolor, const int anisotropy, const float camerabounce, ContentManager & content, std::ostream & error_output) { assert(!loaded); // init drawable load functor LoadDrawable loadDrawable(carpath, anisotropy, content, models, textures, error_output); // load body first const PTree * cfg_body; std::string meshname; std::vector<std::string> texname; if (!cfg.get("body", cfg_body, error_output)) return false; if (!cfg_body->get("mesh", meshname, error_output)) return false; if (!cfg_body->get("texture", texname, error_output)) return false; if (carpaint != "default") texname[0] = carpaint; if (!loadDrawable(meshname, texname, *cfg_body, topnode, &bodynode)) return false; // load wheels const PTree * cfg_wheels; if (!cfg.get("wheel", cfg_wheels, error_output)) return false; std::shared_ptr<PTree> sel_wheel; if (carwheel != "default" && !content.load(sel_wheel, carpath, carwheel)) return false; for (PTree::const_iterator i = cfg_wheels->begin(); i != cfg_wheels->end(); ++i) { const PTree * cfg_wheel = &i->second; // override default wheel with selected, not very efficient, fixme PTree opt_wheel; if (sel_wheel.get()) { opt_wheel.set(*sel_wheel); opt_wheel.merge(*cfg_wheel); cfg_wheel = &opt_wheel; } if (!LoadWheel(*cfg_wheel, loadDrawable, topnode, error_output)) { error_output << "Failed to load wheels." << std::endl; return false; } } // load drawables LoadBody loadBody(topnode, bodynode, loadDrawable); for (PTree::const_iterator i = cfg.begin(); i != cfg.end(); ++i) { if (i->first != "body" && i->first != "steering" && i->first != "light-brake" && i->first != "light-reverse") { loadBody(i->second); } } // load steering wheel const PTree * cfg_steer; if (cfg.get("steering", cfg_steer)) { SceneNode & bodynoderef = topnode.GetNode(bodynode); if (!loadDrawable(*cfg_steer, bodynoderef, &steernode, 0)) { error_output << "Failed to load steering wheel." << std::endl; return false; } cfg_steer->get("max-angle", steer_angle_max); steer_angle_max = steer_angle_max / 180.0 * M_PI; SceneNode & steernoderef = bodynoderef.GetNode(steernode); steer_orientation = steernoderef.GetTransform().GetRotation(); steer_rotation = steer_orientation; } // load brake/reverse light point light sources (optional) int i = 0; std::string istr = "0"; const PTree * cfg_light; while (cfg.get("light-brake-"+istr, cfg_light)) { if (!LoadLight(*cfg_light, content, error_output)) { error_output << "Failed to load lights." << std::endl; return false; } std::ostringstream sstr; sstr << ++i; istr = sstr.str(); } i = 0; istr = "0"; while (cfg.get("light-reverse-"+istr, cfg_light)) { if (!LoadLight(*cfg_light, content, error_output)) { error_output << "Failed to load lights." << std::endl; return false; } std::ostringstream sstr; sstr << ++i; istr = sstr.str(); } // load car brake/reverse graphics (optional) if (cfg.get("light-brake", cfg_light)) { SceneNode & bodynoderef = topnode.GetNode(bodynode); if (!loadDrawable(*cfg_light, bodynoderef, 0, &brakelights)) { error_output << "Failed to load lights." << std::endl; return false; } } if (cfg.get("light-reverse", cfg_light)) { SceneNode & bodynoderef = topnode.GetNode(bodynode); if (!loadDrawable(*cfg_light, bodynoderef, 0, &reverselights)) { error_output << "Failed to load lights." << std::endl; return false; } } if (!LoadCameras(cfg, camerabounce, error_output)) { return false; } SetColor(carcolor[0], carcolor[1], carcolor[2]); loaded = true; return true; }
bool TrackMap::BuildMap( const std::list <RoadStrip> & roads, int w, int h, const std::string & trackname, const std::string & texturepath, ContentManager & content, std::ostream & error_output) { Unload(); const int outsizex = MAP_WIDTH; const int outsizey = MAP_HEIGHT; //find the map width and height map_w_min = +1E6; map_w_max = -1E6; map_h_min = +1E6; map_h_max = -1E6; for (list <RoadStrip>::const_iterator road = roads.begin(); road != roads.end(); road++) { for (vector<RoadPatch>::const_iterator curp = road->GetPatches().begin(); curp != road->GetPatches().end(); curp++) { const Bezier & b = curp->GetPatch(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { const Vec3 & p = b[i + j * 4]; if (p[1] < map_w_min) { map_w_min = p[1]; } if (p[1] > map_w_max) { map_w_max = p[1]; } if (p[0] < map_h_min) { map_h_min = p[0]; } if (p[0] > map_h_max) { map_h_max = p[0]; } } } } } mapsize[0] = map_w_max - map_w_min; mapsize[1] = map_h_max - map_h_min; //determine the scaling factor //we will leave a 1 pixel border float scale_w = (outsizex - 2) / mapsize[0]; float scale_h = (outsizey - 2) / mapsize[1]; scale = (scale_w < scale_h) ? scale_w : scale_h; std::vector<unsigned> pixels(outsizex * outsizey, 0); const int stride = outsizex * sizeof(unsigned); const unsigned color = 0xffffffff; for (list <RoadStrip>::const_iterator road = roads.begin(); road != roads.end(); road++) { for (vector<RoadPatch>::const_iterator curp = road->GetPatches().begin(); curp != road->GetPatches().end(); curp++) { const Bezier & b = curp->GetPatch(); const Vec3 & bl = b.GetBL(); const Vec3 & br = b.GetBR(); const Vec3 & fl = b.GetFL(); const Vec3 & fr = b.GetFR(); float x[6], y[6]; x[2] = (bl[1] - map_w_min) * scale + 1; y[2] = (bl[0] - map_h_min) * scale + 1; x[1] = (fl[1] - map_w_min) * scale + 1; y[1] = (fl[0] - map_h_min) * scale + 1; x[0] = (fr[1] - map_w_min) * scale + 1; y[0] = (fr[0] - map_h_min) * scale + 1; x[3] = x[2]; y[3] = y[2]; x[4] = (br[1] - map_w_min) * scale + 1; y[4] = (br[0] - map_h_min) * scale + 1; x[5] = x[0]; y[5] = y[0]; RasterizeTriangle(x, y, color, &pixels[0], stride); RasterizeTriangle(x + 3, y + 3, color, &pixels[0], stride); } } /* // should operate on alpha only or on each channel? // horizontal blur 3x3 for (int y = 1; y < outsizey - 1; ++y) { unsigned * line = &pixels[0] + y * outsizex; unsigned p = line[0]; for (int x = 1; x < outsizex - 1; ++x) { //unsigned v = (line0[x] + (line1[x] << 1) + line2[x]) >> 2; unsigned v = (line[x-1] >> 2) + (line[x] >> 1) + (line[x+1] >> 2); line[x-1] = p; p = v; } line[outsizex - 2] = p; } // vertical blur 3x3 std::vector<unsigned> linep(outsizex, 0); for (int y = 1; y < outsizey - 1; ++y) { unsigned * line0 = &pixels[0] + (y - 1) * outsizex; unsigned * line1 = &pixels[0] + y * outsizex; unsigned * line2 = &pixels[0] + (y + 1) * outsizex; for (int x = 1; x < outsizex - 1; ++x) { //unsigned v = (line0[x] + (line1[x] << 1) + line2[x]) >> 2; unsigned v = (line0[x] >> 2) + (line1[x] >> 1) + (line2[x] >> 2); line0[x] = linep[x]; linep[x] = v; } } */ //draw a black border around the track const unsigned rgbmask = 0x00ffffff; const unsigned amask = 0xff000000; for (int x = 0; x < outsizex; x++) { for (int y = 0; y < outsizey; y++) { //if this pixel is black if (pixels[outsizex * y + x] == 0) { //if the pixel above this one is non-black if ((y > 0) && ((pixels[outsizex * (y-1) + x] & rgbmask) > 0)) { //set this pixel to non-transparent pixels[outsizex * y + x] |= amask; } //if the pixel left of this one is non-black if ((x > 0) && ((pixels[outsizex * y + x - 1] & rgbmask) > 0)) { //set this pixel to non-transparent pixels[outsizex * y + x] |= amask; } //if the pixel right of this one is non-black if ((x < (outsizex - 1)) && ((pixels[outsizex * y + x + 1] & rgbmask) > 0)) { //set this pixel to non-transparent pixels[outsizex * y + x] |= amask; } //if the pixel below this one is non-black if ((y < (outsizey - 1)) && ((pixels[outsizex * (y+1) + x] & rgbmask) > 0)) { //set this pixel to non-transparent pixels[outsizex * y + x] |= amask; } } } } TextureInfo texinfo; texinfo.data = (unsigned char*)&pixels[0]; texinfo.width = outsizex; texinfo.height = outsizey; texinfo.bytespp = sizeof(unsigned); texinfo.repeatu = false; texinfo.repeatv = false; content.load(track_map, "", trackname, texinfo); //std::cout << "Loading track map dots" << std::endl; TextureInfo dotinfo; content.load(cardot0, texturepath, "cardot0.png", dotinfo); content.load(cardot1, texturepath, "cardot1.png", dotinfo); content.load(cardot0_focused, texturepath, "cardot0_focused.png", dotinfo); content.load(cardot1_focused, texturepath, "cardot1_focused.png", dotinfo); // calculate map position, size screen[0] = (float)w; screen[1] = (float)h; position[0] = 1.0 - MAP_WIDTH / screen[0]; position[1] = 0.12; size[0] = MAP_WIDTH / screen[0]; size[1] = MAP_HEIGHT / screen[1]; dot_size[0] = cardot0->GetW() / 2.0 / screen[0]; dot_size[1] = cardot0->GetH() / 2.0 / screen[1]; mapverts.SetToBillboard(position[0], position[1], position[0]+size[0], position[1]+size[1]); mapdraw = mapnode.GetDrawlist().twodim.insert(Drawable()); Drawable & mapdrawref = mapnode.GetDrawlist().twodim.get(mapdraw); mapdrawref.SetTextures(track_map->GetID()); mapdrawref.SetVertArray(&mapverts); mapdrawref.SetCull(false, false); mapdrawref.SetColor(1,1,1,0.7); mapdrawref.SetDrawOrder(0); return true; }