//////////////////////////////////////////////////////////////////////////////// // Scorched3D (c) 2000-2003 // // This file is part of Scorched3D. // // Scorched3D is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // Scorched3D is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Scorched3D; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include REGISTER_CLASS_SOURCE(GLWPlanView); static const float degToRad = 3.14f / 180.0f; static const float maxAnimationTime = 2.0f; GLWPlanView::GLWPlanView(float x, float y, float w, float h) : GLWidget(x, y, w, h), animationTime_(0.0f), flashTime_(0.0f), totalTime_(0.0f), pointTime_(0.0f), flash_(true), dragging_(false), firstTime_(true) { setToolTip(new GLWTip("Plan View", "Shows the position of the the tanks\n" "on a overhead map of the island.\n" "Flashing tanks are still to make a move.\n" "Clicking on the plan will move the camera\n" "to look at that point.")); } GLWPlanView::~GLWPlanView() { } void GLWPlanView::simulate(float frameTime) { totalTime_ += frameTime; flashTime_ += frameTime; if (flashTime_ > 0.3f) { flashTime_ = 0.0f; flash_ = !flash_; } animationTime_ += frameTime; if (animationTime_ > maxAnimationTime) { animationTime_ = 0.0f; } // Send messages about lines that have been drawn once every // 2 seconds pointTime_ += frameTime; if (pointTime_ > 2.0f) { pointTime_ = 0.0f; if (!sendPoints.empty()) { Vector last = sendPoints.back(); last[2] = 0.0f; ComsLinesMessage message( ScorchedClient::instance()->getTankContainer().getCurrentPlayerId()); message.getLines() = sendPoints; if (dragging_) message.getLines().push_back(Vector::nullVector); sendPoints.clear(); ComsMessageSender::sendToServer(message); if (dragging_) sendPoints.push_back(last); } } // Simulate all points simulateLine(localPoints_); // Local std::list::iterator playeritor; // Remote for (playeritor = dragPoints_.begin(); playeritor != dragPoints_.end(); ) { PlayerDrawnInfo &info = (*playeritor); std::list::iterator recieveitor; for (recieveitor = info.recievepoints.begin(); recieveitor != info.recievepoints.end(); recieveitor++) { Vector &v = (*recieveitor); if (v[2] > 3.0f) v[2] = 3.0f; v[2] -= frameTime; } if (!simulateLine(info)) { playeritor = dragPoints_.erase(playeritor); } else { playeritor++; } } } void GLWPlanView::draw() { if (firstTime_) { firstTime_ = false; if (!OptionsDisplay::instance()->getNoPlanDraw()) { ClientLinesHandler::instance()->registerCallback(this); } } GLWidget::draw(); drawMap(); } void GLWPlanView::drawMap() { GLState currentState(GLState::DEPTH_OFF | GLState::BLEND_ON | GLState::TEXTURE_ON); glPushMatrix(); glTranslatef(x_ + 2.0f, y_ + 2.0f, 0.0f); glScalef(w_ - 4.0f, h_ - 4.0f, 1.0f); drawTexture(); { GLState currentState2(GLState::TEXTURE_OFF); drawCameraPointer(); drawTanks(); drawLines(); } glPopMatrix(); } void GLWPlanView::drawLines() { if (!localPoints_.points.empty()) { localPoints_.playerId = ScorchedClient::instance()-> getTankContainer().getCurrentPlayerId(); drawLine(localPoints_); } if (!dragPoints_.empty()) { std::list::iterator playeritor; for (playeritor = dragPoints_.begin(); playeritor != dragPoints_.end(); playeritor++) { PlayerDrawnInfo &info = (*playeritor); drawLine(info); } } } bool GLWPlanView::simulateLine(PlayerDrawnInfo &info) { while (!info.recievepoints.empty()) { Vector &first = info.recievepoints.front(); if (first[2] > 0.0f) break; first[2] = totalTime_; info.points.push_back(first); info.recievepoints.pop_front(); } while (!info.points.empty()) { Vector &first = info.points.front(); float time = totalTime_ - first[2]; if (time < 3.0f) break; info.points.pop_front(); } return !(info.points.empty() && info.recievepoints.empty()); } void GLWPlanView::drawLine(PlayerDrawnInfo &info) { Tank *current = ScorchedClient::instance()->getTankContainer().getTankById( info.playerId); if (!current) { info.points.clear(); info.recievepoints.clear(); return; } if (info.points.empty()) return; glBegin(GL_LINE_STRIP); std::list::iterator itor; for (itor = info.points.begin(); itor != info.points.end(); itor++) { Vector &v = (*itor); if (v[0] == 0.0f && v[1] == 0.0f) { glEnd(); glBegin(GL_LINE_STRIP); } else { if (v[0] >= 0.0f && v[1] >= 0.0f && v[0] <= 1.0f && v[1] <= 1.0f) { float time = totalTime_ - v[2]; time = 1.0f - (time / 3.0f); glColor4f( current->getColor()[0], current->getColor()[1], current->getColor()[2], time); glVertex2f(v[0], v[1]); } } } glEnd(); } void GLWPlanView::drawTexture() { // Draw the camera pointer float mapWidth = (float) ScorchedClient::instance()-> getLandscapeMaps().getGroundMaps().getMapWidth(); float mapHeight = (float) ScorchedClient::instance()-> getLandscapeMaps().getGroundMaps().getMapHeight(); float maxWidth = MAX(mapWidth, mapHeight); Vector lowerLeft(0.0f, 0.0f, 0.0f); Vector upperRight(mapWidth / maxWidth, mapHeight / maxWidth, 0.0f); lowerLeft[0] += (maxWidth - mapWidth) / maxWidth / 2.0f; upperRight[0] += (maxWidth - mapWidth) / maxWidth / 2.0f; lowerLeft[1] += (maxWidth - mapHeight) / maxWidth / 2.0f; upperRight[1] += (maxWidth - mapHeight) / maxWidth / 2.0f; // Draw the square of land glColor3f(1.0f, 1.0f, 1.0f); Landscape::instance()->getPlanATexture().draw(true); glBegin(GL_QUADS); glTexCoord2f(1.0f, 0.0f); glVertex2f(upperRight[0], lowerLeft[1]); glTexCoord2f(1.0f, 1.0f); glVertex2f(upperRight[0], upperRight[1]); glTexCoord2f(0.0f, 1.0f); glVertex2f(lowerLeft[0], upperRight[1]); glTexCoord2f(0.0f, 0.0f); glVertex2f(lowerLeft[0], lowerLeft[1]); glEnd(); } void GLWPlanView::drawCameraPointer() { // Draw the camera pointer float mapWidth = (float) ScorchedClient::instance()-> getLandscapeMaps().getGroundMaps().getMapWidth(); float mapHeight = (float) ScorchedClient::instance()-> getLandscapeMaps().getGroundMaps().getMapHeight(); float maxWidth = MAX(mapWidth, mapHeight); Vector mid(0.5f, 0.5f); // Get camera positions Vector currentPos = MainCamera::instance()-> getCamera().getCurrentPos(); Vector lookAt = MainCamera::instance()-> getCamera().getLookAt(); Vector direction = (currentPos - lookAt).Normalize2D() * 0.2f; Vector directionPerp = direction.get2DPerp(); // Force camera positions between 0 and 1 currentPos[0] += (maxWidth - mapWidth) / 2.0f; currentPos[1] += (maxWidth - mapHeight) / 2.0f; currentPos[0] /= maxWidth; currentPos[1] /= maxWidth; currentPos[2] = 0.0f; lookAt[0] += (maxWidth - mapWidth) / 2.0f; lookAt[1] += (maxWidth - mapHeight) / 2.0f; lookAt[0] /= maxWidth; lookAt[1] /= maxWidth; lookAt[2] = 0.0f; // Make sure currentpos doesn't go outside boundries currentPos -= mid; float distance = currentPos.Magnitude(); if (distance > 0.5f) { currentPos *= 0.5f / distance; } currentPos += mid; // Make sure look at doesn't go outside boundries lookAt -= mid; distance = lookAt.Magnitude(); if (distance > 0.48f) { lookAt *= 0.48f / distance; } lookAt += mid; // Draw direction arrows glColor3f(0.9f, 0.9f, 1.0f); glBegin(GL_LINES); glVertex3fv(currentPos); glVertex3fv(currentPos - (direction + directionPerp) / 2.0f); glVertex3fv(currentPos); glVertex3fv(currentPos - (direction - directionPerp) / 2.0f); glVertex3fv(currentPos - (direction + directionPerp) / 4.0f); glVertex3fv(currentPos - (direction - directionPerp) / 4.0f); glEnd(); glEnable(GL_LINE_STIPPLE); glLineStipple(1, 0x0F0F); glColor3f(0.7f, 0.7f, 0.7f); glBegin(GL_LINES); glVertex3fv(currentPos); glVertex3fv(lookAt); glEnd(); glDisable(GL_LINE_STIPPLE); } void GLWPlanView::drawTanks() { std::map ¤tTanks = ScorchedClient::instance()->getTankContainer().getPlayingTanks(); if (currentTanks.empty()) return; // Draw the current tank bolder float mapWidth = (float) ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getMapWidth(); float mapHeight = (float) ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getMapHeight(); float maxWidth = MAX(mapWidth, mapHeight); Vector position; drawCurrentTank(); // Draw the rest of the tanks // as points on the plan view glPointSize(5.0f); glBegin(GL_POINTS); bool first = true; std::map::iterator itor; for (itor = currentTanks.begin(); itor != currentTanks.end(); itor++) { Tank *tank = (*itor).second; if (tank->getState().getState() == TankState::sNormal && !tank->getState().getSpectator()) { glColor3fv(tank->getColor()); position = tank->getPosition().getTankPosition(); position[0] += (maxWidth - mapWidth) / 2.0f; position[1] += (maxWidth - mapHeight) / 2.0f; position /= maxWidth; if ((flash_ && tank->getState().getReadyState() == TankState::SNotReady) || tank->getState().getReadyState() == TankState::sReady) { glVertex3fv(position); } TargetRendererImplTank *renderer = (TargetRendererImplTank *) tank->getRenderer(); if (renderer) { GLWToolTip::instance()->addToolTip(&renderer->getTips()->tankTip, GLWTranslate::getPosX() + x_ + position[0] * w_ - 4.0f, GLWTranslate::getPosY() + y_ + position[1] * h_ - 4.0f, 8.0f, 8.0f); } } } glEnd(); } void GLWPlanView::drawCurrentTank() { // Draw the extra rings around the currently playing player // on the plan view // Check that the current player should be shown on the plan Tank *currentTank = ScorchedClient::instance()->getTankContainer().getCurrentTank(); if (!currentTank || currentTank->getState().getState() != TankState::sNormal) return; if (ScorchedClient::instance()->getGameState().getState() != ClientState::StatePlaying) return; // Calculate the constants float mapWidth = (float) ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getMapWidth(); float mapHeight = (float) ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getMapHeight(); float maxWidth = MAX(mapWidth, mapHeight); float scale = animationTime_ / maxAnimationTime; Vector position; float rot = -currentTank->getPosition().getRotationGunXY() * degToRad; position = currentTank->getPosition().getTankPosition(); position[0] += (maxWidth - mapWidth) / 2.0f; position[1] += (maxWidth - mapHeight) / 2.0f; position /= maxWidth; // Build a display list to build the ring // only once static GLuint listNo = 0; if (!listNo) { glNewList(listNo = glGenLists(1), GL_COMPILE); glPointSize(1.0f); glBegin(GL_LINES); for (float a=0; a<=6.28; a+=0.4f) { glVertex2f(sinf(a) * 0.07f, cosf(a) * 0.07f); } glEnd(); glEndList(); } glPushMatrix(); glTranslatef(position[0], position[1], position[2]); // Draw a expanding ring around the current tank glColor3fv(currentTank->getColor()); glPushMatrix(); glScalef(scale, scale, scale); glCallList(listNo); glPopMatrix(); // Draw a line pointing where the current tank is looking glBegin(GL_LINES); glVertex2f(0.0f, 0.0f); glVertex2f( getFastSin(rot) * 0.07f, getFastCos(rot) * 0.07f); glEnd(); glPopMatrix(); } void GLWPlanView::mouseDown(int button, float x, float y, bool &skipRest) { if (inBox(x, y, x_, y_, w_, h_)) { skipRest = true; if (button == 1) { float mapWidth = (float) ScorchedClient::instance()-> getLandscapeMaps().getGroundMaps().getMapWidth(); float mapHeight = (float) ScorchedClient::instance()-> getLandscapeMaps().getGroundMaps().getMapHeight(); float maxWidth = MAX(mapWidth, mapHeight); float mapX = ((x - x_) / w_) * maxWidth; float mapY = ((y - y_) / h_) * maxWidth; mapX -= (maxWidth - mapWidth) / 2.0f; mapY -= (maxWidth - mapHeight) / 2.0f; Vector lookAt(mapX, mapY, ScorchedClient::instance()-> getLandscapeMaps().getGroundMaps().getInterpHeight(mapX, mapY) + 5.0f); MainCamera::instance()->getTarget().setCameraType(TargetCamera::CamFree); MainCamera::instance()->getCamera().setLookAt(lookAt); } else if (button == 4) { dragging_ = true; dragLastX_ = x; dragLastY_ = y; float mapX = ((x - x_) / w_); float mapY = ((y - y_) / h_); localPoints_.points.push_back(Vector(mapX, mapY, totalTime_)); sendPoints.push_back(Vector(mapX, mapY, pointTime_)); } } } void GLWPlanView::mouseDrag(int button, float mx, float my, float x, float y, bool &skipRest) { if (dragging_) { skipRest = true; if (inBox(mx, my, x_, y_, w_, h_)) { if (fabsf(mx - dragLastX_) > 5.0f || fabsf(my - dragLastY_) > 5.0f) { dragLastX_ = mx; dragLastY_ = my; float mapX = ((mx - x_) / w_); float mapY = ((my - y_) / h_); localPoints_.points.push_back(Vector(mapX, mapY, totalTime_)); sendPoints.push_back(Vector(mapX, mapY, pointTime_)); } } } } void GLWPlanView::mouseUp(int button, float x, float y, bool &skipRest) { if (dragging_) { dragging_ = false; localPoints_.points.push_back(Vector::nullVector); sendPoints.push_back(Vector::nullVector); } } void GLWPlanView::addRecievePoints(unsigned int playerId, std::list &recievepoints) { PlayerDrawnInfo *foundInfo = 0; std::list::iterator dragItor; for (dragItor = dragPoints_.begin(); dragItor != dragPoints_.end(); dragItor++) { PlayerDrawnInfo &info = (*dragItor); if (info.playerId == playerId) { foundInfo = &info; } } if (!foundInfo) { dragPoints_.push_back(PlayerDrawnInfo()); foundInfo = &dragPoints_.back(); foundInfo->playerId = playerId; } foundInfo->recievepoints.insert(foundInfo->recievepoints.end(), recievepoints.begin(), recievepoints.end()); }