void primCircleBorder(sdword x, sdword y, sdword radInner, sdword radOuter, sdword nSlices, color colInner) { sdword index; real32 centreX, centreY; double theta, addAmount; real32 radXInner, radXOuter, radYInner, radYOuter; real32 x0, y0, x1, y1, x2, y2; real32 sinTheta, cosTheta; ubyte red = colRed(colInner); ubyte green = colGreen(colInner); ubyte blue = colBlue(colInner); dbgAssert(nSlices >= 3); centreX = primScreenToGLX(x); //make floating-point versions of parameters centreY = primScreenToGLY(y); radXInner = primScreenToGLScaleX(radInner); radYInner = primScreenToGLScaleY(radInner); radXOuter = primScreenToGLScaleX(radOuter); radYOuter = primScreenToGLScaleY(radOuter); addAmount = (double)(2.0f * PI / (real32)(nSlices - 1)); theta = addAmount; x0 = x2 = centreX; y0 = centreY - radYInner; y2 = centreY - radYOuter; glShadeModel(GL_SMOOTH); glEnable(GL_BLEND); for (index = 0; index < nSlices; index++) { glBegin(GL_TRIANGLE_FAN); glColor4ub(red, green, blue, 255); glVertex2f(x0, y0); //2 common points glVertex2f(centreX, centreY); sinTheta = (real32)sin(theta); cosTheta = (real32)cos(theta); x0 = centreX + sinTheta * radXInner; y0 = centreY + cosTheta * radYInner; glVertex2f(x0, y0); //complete glColor4ub(red, green, blue, 0); x1 = centreX + sinTheta * radXOuter; y1 = centreY + cosTheta * radYOuter; glVertex2f(x1, y1); //complete glVertex2f(x2, y2); x2 = x1; y2 = y1; glEnd(); theta += addAmount; } glDisable(GL_BLEND); glShadeModel(GL_FLAT); }
/*----------------------------------------------------------------------------- Name : pingStartup Description : Startup the ping module Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void pingStartup(void) { scriptSet(NULL, "ping.script", pingTweaks); pingAnomalyMinScreenSize = primScreenToGLScaleX(pingAnomalyMinScreenSize); pingNewShipMinScreenSize = primScreenToGLScaleX(pingNewShipMinScreenSize); pingBattleMinScreenSize = primScreenToGLScaleX(pingBattleMinScreenSize); pingTaskHandle = taskStart(pingUpdateTask, PNG_TaskPeriod, 0); listInit(&pingList); pingReset(); }
/*----------------------------------------------------------------------------- Name : partCircleSolid2 Description : Render a 2d circle, like the 3D one. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void primCircleSolid2(sdword x, sdword y, sdword rad, sdword nSlices, color c) { sdword index; GLfloat v[3]; double theta; vector centre; real32 radiusX, radiusY; bool cull; if (glcActive()) { rectangle r; r.x0 = x - rad; r.y0 = y - rad; r.x1 = x + rad; r.y1 = y + rad; glcRectSolid2(&r, c); return; } cull = glIsEnabled(GL_CULL_FACE) ? TRUE : FALSE; centre.x = primScreenToGLX(x); centre.y = primScreenToGLY(y); radiusX = primScreenToGLScaleX(rad); radiusY = primScreenToGLScaleY(rad); glColor4ub(colRed(c), colGreen(c), colBlue(c), colAlpha(c)); v[0] = centre.x; v[1] = centre.y; glDisable(GL_CULL_FACE); glBegin(GL_TRIANGLE_FAN); glVertex2f(v[0], v[1]); for (index = 0, theta = 0.0; index < nSlices; index++) { v[0] = centre.x + (real32)(sin(theta)) * radiusX; v[1] = centre.y + (real32)(cos(theta)) * radiusY; theta += 2.0 * PI / (double)nSlices; glVertex2f(v[0], v[1]); } v[0] = centre.x; v[1] = centre.y + radiusY; glVertex2f(v[0], v[1]); glEnd(); if (cull) { glEnable(GL_CULL_FACE); } }
/*----------------------------------------------------------------------------- Name : primOvalArcOutline2 Description : Draw an outline section of an oval. Inputs : o - oval structure describing location and size on-screen degStarts, degEnd - degree stations of start and end of line thickness - thickness of lines segments - number of line segments for a complete oval c - color to draw outline in Outputs : .. Return : void Note : The coordinate system used will be the engineering system where up (x = 0, y = -1) is 0 rad. ----------------------------------------------------------------------------*/ void primOvalArcOutline2(oval *o, real32 radStart, real32 radEnd, sdword thickness, sdword segments, color c) { sdword segment, endSegment; real32 angle, angleInc; real32 centreX, centreY, width, height; real32 x, y, lastX, lastY; if (glcActive()) { centreX = (real32)o->centreX; centreY = (real32)o->centreY; width = (real32)o->radiusX; height = (real32)o->radiusY; } else { centreX = primScreenToGLX(o->centreX); //get floating-point version of oval attributes centreY = primScreenToGLY(o->centreY); width = primScreenToGLScaleX(o->radiusX); height = primScreenToGLScaleY(o->radiusY); } segment = (sdword)(radStart * (real32)segments / (2.0f * PI));//get starting segment endSegment = (sdword)(radEnd * (real32)segments / (2.0f * PI) - 0.01f);//get ending segment glColor3ub(colRed(c), colGreen(c), colBlue(c)); glPushAttrib(GL_LINE_BIT); glLineWidth((GLfloat)thickness); glBegin(GL_LINE_STRIP); x = centreX + (real32)sin((double)radStart) * width; //first vertex y = centreY + (real32)cos((double)radStart) * height; if (glcActive()) { lastX = x; lastY = y; } else { glVertex2f(x, y); } segment++; angle = (real32)segment * (2.0f * PI / (real32)segments); angleInc = (2.0f * PI / (real32)segments); for (; segment <= endSegment; segment++) { //for start and all complete segments x = centreX + (real32)sin((double)angle) * width; y = centreY + (real32)cos((double)angle) * height; if (glcActive()) { glcLine2((sdword)lastX, (sdword)lastY, (sdword)x, (sdword)y, thickness, c); lastX = x; lastY = y; } else { glVertex2f(x, y); } angle += angleInc; //update angle } x = centreX + (real32)sin((double)radEnd) * width; y = centreY + (real32)cos((double)radEnd) * height; if (glcActive()) { glcLine2((sdword)lastX, (sdword)lastY, (sdword)x, (sdword)y, thickness, c); } else { glVertex2f(x, y); //draw last vertex } glEnd(); glPopAttrib(); }
/*----------------------------------------------------------------------------- Name : pingListDraw Description : Draw all pings from farthest to nearest. Inputs : camera - the camera we're rendering from modelView, projection - current matrices viewPort - rectangle we're rending in, for the TO legend Outputs : Return : Note : The renderer should be in 2D mode at this point. ----------------------------------------------------------------------------*/ void pingListDraw(Camera *camera, hmatrix *modelView, hmatrix *projection, rectangle *viewPort) { real32 pingAge, pingCycle, pingMod, pingSize; real32 x, y, radius; Node *thisNode, *nextNode; ping *thisPing; vector distSquared; sdword nSegments, index, rowHeight, xScreen, yScreen; oval o; udword TOFlags = 0; fonthandle fhSave; toicon *icon; color col; real32 realMargin; ShipClass shipClass; static real32 lastProximityPing = REALlyBig; static real32 lastAnomolyPing = REALlyBig; static real32 lastBattlePing = REALlyBig; static real32 lastHyperspacePing = REALlyBig; static real32 lastNewshipPing = REALlyBig; bool pingset; //start by sorting the ping list from farthest to nearest thisNode = pingList.head; while (thisNode != NULL) { //scan all pings nextNode = thisNode->next; thisPing = listGetStructOfNode(thisNode); if (thisPing->owner != NULL) { thisPing->centre = thisPing->owner->posinfo.position; } vecSub(distSquared, camera->eyeposition, thisPing->centre); thisPing->cameraDistanceSquared = vecMagnitudeSquared(distSquared); TOFlags |= thisPing->TOMask; thisNode = nextNode; } listMergeSortGeneral(&pingList, pingListSortCallback); //now the list is sorted; proceed to draw all the pings thisNode = pingList.head; pingset = FALSE; while (thisNode != NULL) { //scan all pings nextNode = thisNode->next; thisPing = listGetStructOfNode(thisNode); pingCycle = thisPing->pingDuration + thisPing->interPingPause; pingAge = universe.totaltimeelapsed - thisPing->creationTime; pingMod = (real32)fmod((double)pingAge, (double)pingCycle); if (pingMod <= thisPing->pingDuration) { pingSize = (thisPing->size - thisPing->minSize) * pingMod / thisPing->pingDuration + thisPing->minSize; selCircleComputeGeneral(modelView, projection, &thisPing->centre, max(thisPing->size,thisPing->minSize), &x, &y, &radius); if (radius > 0.0f) { radius = max(radius, thisPing->minScreenSize); radius *= pingSize / max(thisPing->size,thisPing->minSize); o.centreX = primGLToScreenX(x); o.centreY = primGLToScreenY(y); o.radiusX = o.radiusY = primGLToScreenScaleX(radius); nSegments = pieCircleSegmentsCompute(radius); primOvalArcOutline2(&o, 0.0f, 2*PI, 1, nSegments, thisPing->c); /* starting to draw a new ping so play the sound */ if (!smZoomingIn && !smZoomingOut && !pingset) { switch (thisPing->TOMask) { case PTOM_Anomaly: if (pingSize <=lastAnomolyPing) { soundEvent(NULL, UI_SensorsPing); pingset = TRUE; lastAnomolyPing = pingSize; } break; case PTOM_Battle: if (pingSize <= lastBattlePing) { soundEvent(NULL, UI_PingBattle); pingset = TRUE; lastBattlePing = pingSize; } break; case PTOM_Hyperspace: if (pingSize <= lastHyperspacePing) { soundEvent(NULL, UI_PingHyperspace); pingset = TRUE; lastHyperspacePing = pingSize; } break; case PTOM_Proximity: if (pingSize <= lastProximityPing) { soundEvent(NULL, UI_PingProximity); pingset = TRUE; lastProximityPing = pingSize; } break; case PTOM_NewShips: if (pingSize <= lastNewshipPing) { soundEvent(NULL, UI_PingNewShips); pingset = TRUE; lastNewshipPing = pingSize; } break; default: break; } } } } thisNode = nextNode; } //draw the blip TO if (smTacticalOverlay) { realMargin = primScreenToGLScaleX(viewPort->x0); fhSave = fontCurrentGet(); //save the current font fontMakeCurrent(selGroupFont2); // use a common, fairly small font rowHeight = fontHeight("M"); // used to space the legend yScreen = viewPort->y0 + rowHeight; //leave some space at the top to start radius = primScreenToGLScaleX(rowHeight)/2; xScreen = viewPort->x0 + (sdword)(rowHeight * 2.5); for (index = 0; index < PTO_NumberTOs; index++) { if ((TOFlags & pingTOList[index].bitMask)) { // fontPrint(xScreen, yScreen, *pingTOList[index].c, "O"); pingTOList[index].lastTimeDrawn = universe.totaltimeelapsed; } if (universe.totaltimeelapsed - pingTOList[index].lastTimeDrawn <= pingTOLingerTime) { o.centreX = viewPort->x0 + rowHeight * 3 / 2; o.centreY = yScreen + rowHeight / 2; o.radiusX = o.radiusY = rowHeight / 2; primOvalArcOutline2(&o, 0.0f, TWOPI, 1, pingTONSegments, *pingTOList[index].c); fontPrint(xScreen, yScreen, TO_TextColor, strGetString(pingTOList[index].stringEnum)); yScreen += rowHeight + 1; } } for (shipClass = 0; shipClass < NUM_CLASSES; shipClass++) { if (!toClassUsed[shipClass][0]) { continue; } icon = toClassIcon[shipClass]; fontPrint(xScreen, yScreen + (rowHeight>>2), TO_TextColor, ShipClassToNiceStr(shipClass)); #if TO_STANDARD_COLORS col = teFriendlyColor; #else col = teColorSchemes[universe.curPlayerIndex].tacticalColor; #endif col = colRGB(colRed(col)/TO_IconColorFade, colGreen(col)/TO_IconColorFade, colBlue(col)/TO_IconColorFade); primLineLoopStart2(1, col); for (index = icon->nPoints - 1; index >= 0; index--) { primLineLoopPoint3F(realMargin + primScreenToGLX(rowHeight*1.5) + icon->loc[index].x * radius, primScreenToGLY(yScreen + rowHeight/2) + icon->loc[index].y * radius); } primLineLoopEnd2(); yScreen += rowHeight + 1; } fontMakeCurrent(fhSave); } }