/* ================= R_DrawSpriteModel ================= */ void R_DrawSpriteModel (entity_t *e) { float alpha = 1.0f; vec2_t texCoord[4]; vec3_t point[4]; dsprite_t *psprite; dsprframe_t *frame; float *up, *right; int i; // don't even bother culling, because it's just a single // polygon without a surface cache psprite = (dsprite_t *)currentmodel->extradata; e->frame %= psprite->numframes; frame = &psprite->frames[e->frame]; if (!frame) return; c_alias_polys += 2; // normal sprite up = vup; right = vright; if (e->flags & RF_TRANSLUCENT) alpha = e->alpha; R_SetVertexRGBScale (true); // Psychospaz's additive transparency if ((currententity->flags & RF_TRANS_ADDITIVE) && (alpha != 1.0f)) { GL_Enable (GL_BLEND); GL_TexEnv (GL_MODULATE); GL_Disable (GL_ALPHA_TEST); GL_DepthMask (false); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE); } else { GL_TexEnv (GL_MODULATE); if (alpha == 1.0f) { GL_Enable (GL_ALPHA_TEST); GL_DepthMask (true); } else { GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_DepthMask (false); GL_Enable (GL_BLEND); GL_Disable (GL_ALPHA_TEST); } } GL_Bind(currentmodel->skins[0][e->frame]->texnum); Vector2Set(texCoord[0], 0, 1); Vector2Set(texCoord[1], 0, 0); Vector2Set(texCoord[2], 1, 0); Vector2Set(texCoord[3], 1, 1); VectorMA (e->origin, -frame->origin_y, up, point[0]); VectorMA (point[0], -frame->origin_x, right, point[0]); VectorMA (e->origin, frame->height - frame->origin_y, up, point[1]); VectorMA (point[1], -frame->origin_x, right, point[1]); VectorMA (e->origin, frame->height - frame->origin_y, up, point[2]); VectorMA (point[2], frame->width - frame->origin_x, right, point[2]); VectorMA (e->origin, -frame->origin_y, up, point[3]); VectorMA (point[3], frame->width - frame->origin_x, right, point[3]); rb_vertex = rb_index = 0; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+1; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+3; for (i=0; i<4; i++) { VA_SetElem2(texCoordArray[0][rb_vertex], texCoord[i][0], texCoord[i][1]); VA_SetElem3(vertexArray[rb_vertex], point[i][0], point[i][1], point[i][2]); VA_SetElem4(colorArray[rb_vertex], 1.0f, 1.0f, 1.0f, alpha); rb_vertex++; } RB_DrawArrays (); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv (GL_REPLACE); GL_DepthMask (true); GL_Disable (GL_ALPHA_TEST); GL_Disable (GL_BLEND); R_SetVertexRGBScale (false); RB_DrawMeshTris (); rb_vertex = rb_index = 0; }
/** * @brief Get the width of radar. * @param[in] node Node description of the radar * @param[in] gridSize size of the radar picture, in grid units. * @sa UI_InitRadar */ static void UI_GetRadarWidth (const uiNode_t *node, vec2_t gridSize) { int j; int tileWidth[2]; /**< Contains the width of the first and the last tile of the first line (in screen unit) */ int tileHeight[2]; /**< Contains the height of the first and the last tile of the first column (in screen unit)*/ int secondTileGridX; /**< Contains the grid X position of 2nd tiles in first line */ int secondTileGridY; /**< Contains the grid Y position of 2nd tiles in first column */ float ratioConversion; /**< ratio conversion between screen coordinates and grid coordinates */ const int ROUNDING_PIXEL = 1; /**< Number of pixel to remove to avoid rounding errors (and lines between tiles) * We remove pixel because this is much nicer if tiles overlap a little bit rather than * if they are too distant one from the other */ /* Set radar.gridMax */ radar.gridMax[0] = radar.gridMin[0]; radar.gridMax[1] = radar.gridMin[1]; /* Initialize secondTileGridX to value higher that real value */ secondTileGridX = radar.gridMin[0] + 1000; secondTileGridY = radar.gridMin[1] + 1000; /* Initialize screen size of last tile (will be used only if there is 1 tile in a line or in a row) */ Vector2Set(tileWidth, 0, 0); Vector2Set(tileHeight, 0, 0); for (j = 0; j < radar.numImages; j++) { const hudRadarImage_t *image = &radar.images[j]; assert(image->gridX >= radar.gridMin[0]); assert(image->gridY >= radar.gridMin[1]); /* we can assume this because every random map tile has it's origin in * (0, 0) and therefore there are no intersections possible on the min * x and the min y axis. We just have to add the image->w and image->h * values of those images that are placed on the gridMin values. * This also works for static maps, because they have a gridX and gridY * value of zero */ if (image->gridX == radar.gridMin[0]) { /* radar.gridMax[1] is the maximum for FIRST column (maximum depends on column) */ if (image->gridY > radar.gridMax[1]) { tileHeight[1] = image->height; radar.gridMax[1] = image->gridY; } if (image->gridY == radar.gridMin[1]) { /* This is the tile of the map in the lower left: */ tileHeight[0] = image->height; tileWidth[0] = image->width; } else if (image->gridY < secondTileGridY) secondTileGridY = image->gridY; } if (image->gridY == radar.gridMin[1]) { /* radar.gridMax[1] is the maximum for FIRST line (maximum depends on line) */ if (image->gridX > radar.gridMax[0]) { tileWidth[1] = image->width; radar.gridMax[0] = image->gridX; } else if (image->gridX < secondTileGridX) secondTileGridX = image->gridX; } } /* Maybe there was only one tile in a line or in a column? */ if (!tileHeight[1]) tileHeight[1] = tileHeight[0]; if (!tileWidth[1]) tileWidth[1] = tileWidth[0]; /* Now we get the ratio conversion between screen coordinates and grid coordinates. * The problem is that some tiles may have L or T shape. * But we now that the tile in the lower left follows for sure the side of the map on it's whole length * at least either on its height or on its width.*/ ratioConversion = std::max((secondTileGridX - radar.gridMin[0]) / (tileWidth[0] - ROUNDING_PIXEL), (secondTileGridY - radar.gridMin[1]) / (tileHeight[0] - ROUNDING_PIXEL)); /* And now we fill radar.w and radar.h */ radar.w = floor((radar.gridMax[0] - radar.gridMin[0]) / ratioConversion) + tileWidth[1]; radar.h = floor((radar.gridMax[1] - radar.gridMin[1]) / ratioConversion) + tileHeight[1]; Vector2Set(gridSize, round(radar.w * ratioConversion), round(radar.h * ratioConversion)); }
/** * @brief Draws the image node * @param[in] node The UI node to draw */ void uiImageNode::draw (uiNode_t* node) { vec2_t size; vec2_t nodepos; const image_t* image; vec2_t imagepos; vec2_t nodesize; const char* imageName = UI_GetReferenceString(node, node->image); if (Q_strnull(imageName)) return; image = UI_LoadImage(imageName); if (!image) return; /* mouse darken effect */ /** @todo convert all pic using mousefx into button. * @todo delete mousefx */ #if 0 if (node->mousefx && node->state) { vec4_t color; VectorScale(node->color, 0.8, color); color[3] = node->color[3]; R_Color(color); } #endif UI_GetNodeAbsPos(node, nodepos); Vector2Copy(node->box.size, nodesize); nodesize[0] -= node->padding + node->padding; if (nodesize[0] < 0) nodesize[0] = 0; nodesize[1] -= node->padding + node->padding; if (nodesize[1] < 0) nodesize[1] = 0; /** @todo code is duplicated in the ekg node code */ if (node->box.size[0] && !node->box.size[1]) { const float scale = image->width / node->box.size[0]; Vector2Set(size, node->box.size[0], image->height / scale); } else if (node->box.size[1] && !node->box.size[0]) { const float scale = image->height / node->box.size[1]; Vector2Set(size, image->width / scale, node->box.size[1]); } else { Vector2Copy(nodesize, size); if (EXTRADATA(node).preventRatio) { /* maximize the image into the bounding box */ const float ratio = (float) image->width / (float) image->height; if (size[1] * ratio > size[0]) { Vector2Set(size, size[0], size[0] / ratio); } else { Vector2Set(size, size[1] * ratio, size[1]); } } } UI_ImageAlignBoxInBox(nodepos, nodesize, size, (align_t) node->contentAlign, imagepos); UI_DrawNormImage(false, imagepos[0] + node->padding, imagepos[1] + node->padding, size[0], size[1], EXTRADATA(node).texh[0], EXTRADATA(node).texh[1], EXTRADATA(node).texl[0], EXTRADATA(node).texl[1], image); /** @todo convert all pic using mousefx into button. * @todo delete mousefx */ #if 0 if (node->mousefx && node->state) { R_Color(nullptr); } #endif }
static void UI_KeyBindingNodeDraw (uiNode_t *node) { static const int panelTemplate[] = { CORNER_SIZE, MID_SIZE, CORNER_SIZE, CORNER_SIZE, MID_SIZE, CORNER_SIZE, MARGE }; const char *binding, *description, *command; int texX, texY; const float *textColor; const char *image; vec2_t pos; const char *font = UI_GetFontFromNode(node); const int bindingWidth = EXTRADATA(node).bindingWidth; const int descriptionWidth = node->size[0] - bindingWidth; vec2_t descriptionPos, descriptionSize; vec2_t bindingPos, bindingSize; if (node->state) { textColor = node->color; texX = TILE_SIZE; texY = 0; } else { textColor = node->color; texX = 0; texY = 0; } if (UI_HasFocus(node)) textColor = node->selectedColor; UI_GetNodeAbsPos(node, pos); Vector2Set(descriptionSize, descriptionWidth, node->size[1]); Vector2Set(bindingSize, bindingWidth, node->size[1]); Vector2Set(descriptionPos, pos[0], pos[1]); Vector2Set(bindingPos, pos[0] + descriptionWidth + node->padding, pos[1]); image = UI_GetReferenceString(node, node->image); if (image) { UI_DrawPanel(descriptionPos, descriptionSize, image, texX, texY, panelTemplate); UI_DrawPanel(bindingPos, bindingSize, image, texX, texY, panelTemplate); } binding = UI_GetReferenceString(node, node->text); if (Q_strnull(binding)) binding = _("NONE"); /** @todo check that this is a keybinding value (with macro expansion) */ command = node->text + 9; description = Cmd_GetCommandDesc(command); if (description[0] == '\0') description = command; R_Color(textColor); UI_DrawStringInBox(font, node->contentAlign, descriptionPos[0] + node->padding, descriptionPos[1] + node->padding, descriptionSize[0] - node->padding - node->padding, descriptionSize[1] - node->padding - node->padding, description, LONGLINES_PRETTYCHOP); UI_DrawStringInBox(font, node->contentAlign, bindingPos[0] + node->padding, bindingPos[1] + node->padding, bindingSize[0] - node->padding - node->padding, bindingSize[1] - node->padding - node->padding, binding, LONGLINES_PRETTYCHOP); R_Color(NULL); }
void CG_DoGlass( vector3 verts[4], vector3 *normal, vector3 *dmgPt, vector3 *dmgDir, float dmgRadius, int maxShards ) { int i, t; int mxHeight, mxWidth; float height, width; float stepWidth, stepHeight; float timeDecay; float x, z; float xx, zz; float dif; int time = 0; int glassShards = 0; qboolean stick = qtrue; vector3 subVerts[4]; vector2 biPoints[4]; // To do a smarter tesselation, we should figure out the relative height and width of the brush face, // then use this to pick a lod value from 1-3 in each axis. This will give us 1-9 lod levels, which will // hopefully be sufficient. CG_CalcHeightWidth( verts, &height, &width ); trap_S_StartSound( dmgPt, -1, CHAN_AUTO, trap_S_RegisterSound("sound/effects/glassbreak1.wav")); // Pick "LOD" for height if ( height < 100 ) { stepHeight = 0.2f; mxHeight = 5; timeDecay = TIME_DECAY_SLOW; } else if ( height > 220 ) { stepHeight = 0.05f; mxHeight = 20; timeDecay = TIME_DECAY_FAST; } else { stepHeight = 0.1f; mxHeight = 10; timeDecay = TIME_DECAY_MED; } // Pick "LOD" for width /* if ( width < 100 ) { stepWidth = 0.2f; mxWidth = 5; timeDecay = ( timeDecay + TIME_DECAY_SLOW ) * 0.5f; } else if ( width > 220 ) { stepWidth = 0.05f; mxWidth = 20; timeDecay = ( timeDecay + TIME_DECAY_FAST ) * 0.5f; } else { stepWidth = 0.1f; mxWidth = 10; timeDecay = ( timeDecay + TIME_DECAY_MED ) * 0.5f; } */ //Attempt to scale the glass directly to the size of the window stepWidth = (0.25f - (width*0.0002)); //(width*0.0005)); mxWidth = width*0.2; timeDecay = ( timeDecay + TIME_DECAY_FAST ) * 0.5f; if (stepWidth < 0.01f) { stepWidth = 0.01f; } if (mxWidth < 5) { mxWidth = 5; } for ( z = 0.0f, i = 0; z < 1.0f; z += stepHeight, i++ ) { for ( x = 0.0f, t = 0; x < 1.0f; x += stepWidth, t++ ) { // This is nasty.. if ( t > 0 && t < mxWidth ) { xx = x - offX[i][t]; } else { xx = x; } if ( i > 0 && i < mxHeight ) { zz = z - offZ[t][i]; } else { zz = z; } Vector2Set( &biPoints[0], xx, zz ); if ( t + 1 > 0 && t + 1 < mxWidth ) { xx = x - offX[i][t + 1]; } else { xx = x; } if ( i > 0 && i < mxHeight ) { zz = z - offZ[t + 1][i]; } else { zz = z; } Vector2Set( &biPoints[1], xx + stepWidth, zz ); if ( t + 1 > 0 && t + 1 < mxWidth ) { xx = x - offX[i + 1][t + 1]; } else { xx = x; } if ( i + 1 > 0 && i + 1 < mxHeight ) { zz = z - offZ[t + 1][i + 1]; } else { zz = z; } Vector2Set( &biPoints[2], xx + stepWidth, zz + stepHeight); if ( t > 0 && t < mxWidth ) { xx = x - offX[i + 1][t]; } else { xx = x; } if ( i + 1 > 0 && i + 1 < mxHeight ) { zz = z - offZ[t][i + 1]; } else { zz = z; } Vector2Set( &biPoints[3], xx, zz + stepHeight ); CG_CalcBiLerp( verts, subVerts, biPoints ); dif = DistanceSquared( &subVerts[0], dmgPt ) * timeDecay - random() * 32; // If we decrease dif, we are increasing the impact area, making it more likely to blow out large holes dif -= dmgRadius * dmgRadius; if ( dif > 1 ) { stick = qtrue; time = dif + random() * 200; } else { stick = qfalse; time = 0; } CG_DoGlassQuad( subVerts, biPoints, stick, time, dmgDir ); glassShards++; if (maxShards && glassShards >= maxShards) { return; } } } }
void R_DrawCameraEffect (void) { image_t *image[2]; int32_t x, y, w, h, i, j; float texparms[2][4]; vec2_t texCoord[4]; vec3_t verts[4]; renderparms_t cameraParms; image[0] = R_DrawFindPic ("/gfx/2d/screenstatic.tga"); image[1] = R_DrawFindPic ("/gfx/2d/scanlines.tga"); if (!image[0] || !image[1]) return; x = y = 0; w = vid.width; h = vid.height; GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_BlendFunc (GL_DST_COLOR, GL_SRC_COLOR); GL_DepthMask (false); VectorSet(verts[0], x, y, 0); VectorSet(verts[1], x+w, y, 0); VectorSet(verts[2], x+w, y+h, 0); VectorSet(verts[3], x, y+h, 0); Vector4Set(texparms[0], 2, 2, -30, 10); Vector4Set(texparms[1], 1, 10, 0, 0); rb_vertex = rb_index = 0; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+1; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+3; rb_vertex = 4; for (i=0; i<2; i++) { GL_Bind (image[i]->texnum); Vector2Set(texCoord[0], x/image[i]->width, y/image[i]->height); Vector2Set(texCoord[1], (x+w)/image[i]->width, y/image[i]->height); Vector2Set(texCoord[2], (x+w)/image[i]->width, (y+h)/image[i]->height); Vector2Set(texCoord[3], x/image[i]->width, (y+h)/image[i]->height); Mod_SetRenderParmsDefaults (&cameraParms); cameraParms.scale_x = texparms[i][0]; cameraParms.scale_y = texparms[i][1]; cameraParms.scroll_x = texparms[i][2]; cameraParms.scroll_y = texparms[i][3]; RB_ModifyTextureCoords (&texCoord[0][0], &verts[0][0], 4, cameraParms); for (j=0; j<4; j++) { VA_SetElem2(texCoordArray[0][j], texCoord[j][0], texCoord[j][1]); VA_SetElem3(vertexArray[j], verts[j][0], verts[j][1], verts[j][2]); VA_SetElem4(colorArray[j], 1, 1, 1, 1); } RB_DrawArrays (); } rb_vertex = rb_index = 0; GL_DepthMask (true); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_Disable (GL_BLEND); GL_TexEnv (GL_REPLACE); GL_Enable (GL_ALPHA_TEST); }
/* ============= R_DrawScaledImage Psychospaz's code for drawing stretched crosshairs ============= */ void R_DrawScaledImage (int32_t x, int32_t y, float scale, float alpha, image_t *gl) { float xoff, yoff; float scale_x, scale_y; int32_t i; vec2_t texCoord[4], verts[4]; if (scrap_dirty) Scrap_Upload (); // add alpha support if (gl->has_alpha || alpha < 1.0) { GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_DepthMask (false); } GL_Bind (gl->texnum); scale_x = scale_y = scale; scale_x *= gl->replace_scale_w; // scale down if replacing a pcx image scale_y *= gl->replace_scale_h; // scale down if replacing a pcx image Vector2Set(texCoord[0], gl->sl, gl->tl); Vector2Set(texCoord[1], gl->sh, gl->tl); Vector2Set(texCoord[2], gl->sh, gl->th); Vector2Set(texCoord[3], gl->sl, gl->th); xoff = gl->width*scale_x-gl->width; yoff = gl->height*scale_y-gl->height; Vector2Set(verts[0], x, y); Vector2Set(verts[1], x+gl->width+xoff, y); Vector2Set(verts[2], x+gl->width+xoff, y+gl->height+yoff); Vector2Set(verts[3], x, y+gl->height+yoff); rb_vertex = rb_index = 0; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+1; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+3; for (i=0; i<4; i++) { VA_SetElem2(texCoordArray[0][rb_vertex], texCoord[i][0], texCoord[i][1]); VA_SetElem3(vertexArray[rb_vertex], verts[i][0], verts[i][1], 0); VA_SetElem4(colorArray[rb_vertex], 1.0, 1.0, 1.0, alpha); rb_vertex++; } RB_RenderMeshGeneric (false); if (gl->has_alpha || alpha < 1.0) { GL_DepthMask (true); GL_TexEnv (GL_REPLACE); GL_Disable (GL_BLEND); GL_Enable (GL_ALPHA_TEST); // add alpha support } }
/* ================ R_DrawChar Draws one variable sized graphics character with 0 being transparent. It can be clipped to the top of the screen to allow the console to be smoothly scrolled off. ================ */ void R_DrawChar (float x, float y, int32_t num, float scale, int32_t red, int32_t green, int32_t blue, int32_t alpha, qboolean italic, qboolean last) { int32_t row, col, i; float frow, fcol, size, cscale, italicAdd; vec2_t texCoord[4], verts[4]; qboolean addChar = true; num &= 255; if (alpha > 255) alpha = 255; else if (alpha < 1) alpha = 1; if ((num & 127) == 32) // space addChar = false; if (y <= -(scale * DEFAULT_FONT_SIZE)) // totally off screen addChar = false; row = num >> 4; col = num&15; frow = row*0.0625; fcol = col*0.0625; size = 0.0625; cscale = scale * DEFAULT_FONT_SIZE; italicAdd = (italic) ? (cscale*0.25) : 0; if (addChar) { Vector2Set(texCoord[0], fcol, frow); Vector2Set(texCoord[1], fcol + size, frow); Vector2Set(texCoord[2], fcol + size, frow + size); Vector2Set(texCoord[3], fcol, frow + size); Vector2Set(verts[0], x+italicAdd, y); Vector2Set(verts[1], x+cscale+italicAdd, y); Vector2Set(verts[2], x+cscale-italicAdd, y+cscale); Vector2Set(verts[3], x-italicAdd, y+cscale); if (char_count == 0) rb_vertex = rb_index = 0; if (rb_vertex + 4 >= MAX_VERTICES || rb_index + 6 >= MAX_INDICES) R_FlushChars (); indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+1; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+0; indexArray[rb_index++] = rb_vertex+2; indexArray[rb_index++] = rb_vertex+3; for (i=0; i<4; i++) { VA_SetElem2(texCoordArray[0][rb_vertex], texCoord[i][0], texCoord[i][1]); VA_SetElem3(vertexArray[rb_vertex], verts[i][0], verts[i][1], 0); VA_SetElem4(colorArray[rb_vertex], red*DIV255, green*DIV255, blue*DIV255, alpha*DIV255); rb_vertex++; } char_count++; } if (last) R_FlushChars (); }
void CG_DoGlass( vec3_t verts[4], vec3_t normal, vec3_t dmgPt, vec3_t dmgDir, float dmgRadius ) { int i, t; int mxHeight, mxWidth; float height, width; float stepWidth, stepHeight; float timeDecay; float x, z; float xx, zz; int time = 0; bool stick = true; vec3_t subVerts[4]; vec2_t biPoints[4]; // To do a smarter tesselation, we should figure out the relative height and width of the brush face, // then use this to pick a lod value from 1-3 in each axis. This will give us 1-9 lod levels, which will // hopefully be sufficient. CG_CalcHeightWidth( verts, &height, &width ); cgi_S_StartSound( dmgPt, -1, CHAN_AUTO, cgi_S_RegisterSound("sound/effects/glassbreak1.wav")); // Pick "LOD" for height if ( height < 100 ) { stepHeight = 0.2f; mxHeight = 5; timeDecay = TIME_DECAY_SLOW; } /* else if ( height > 220 ) // was originally mxHeight = 20....but removing this whole section because it causes huge number of chunks...which is bad { stepHeight = 0.075f; mxHeight = 15; timeDecay = TIME_DECAY_FAST; }*/ else { stepHeight = 0.1f; mxHeight = 10; timeDecay = TIME_DECAY_MED; } // Pick "LOD" for width if ( width < 100 ) { stepWidth = 0.2f; mxWidth = 5; timeDecay = ( timeDecay + TIME_DECAY_SLOW ) * 0.5f; } /* else if ( width > 220 ) // don't do this because it causes too much chug with large glass panes...especially when more than one pane can be broken at a time { stepWidth = 0.075f; mxWidth = 15; timeDecay = ( timeDecay + TIME_DECAY_FAST ) * 0.5f; }*/ else { stepWidth = 0.1f; mxWidth = 10; timeDecay = ( timeDecay + TIME_DECAY_MED ) * 0.5f; } for ( z = 0.0f, i = 0; z < 1.0f; z += stepHeight, i++ ) { for ( x = 0.0f, t = 0; x < 1.0f; x += stepWidth, t++ ) { // This is nasty..we do this because we don't want to add a random offset on the edge of the glass brush // ...but we do in the center, otherwise the breaking scheme looks way too orderly if ( t > 0 && t < mxWidth ) { xx = x - offX[i][t]; } else { xx = x; } if ( i > 0 && i < mxHeight ) { zz = z - offZ[t][i]; } else { zz = z; } Vector2Set( biPoints[0], xx, zz ); if ( t + 1 > 0 && t + 1 < mxWidth ) { xx = x - offX[i][t + 1]; } else { xx = x; } if ( i > 0 && i < mxHeight ) { zz = z - offZ[t + 1][i]; } else { zz = z; } Vector2Set( biPoints[1], xx + stepWidth, zz ); if ( t + 1 > 0 && t + 1 < mxWidth ) { xx = x - offX[i + 1][t + 1]; } else { xx = x; } if ( i + 1 > 0 && i + 1 < mxHeight ) { zz = z - offZ[t + 1][i + 1]; } else { zz = z; } Vector2Set( biPoints[2], xx + stepWidth, zz + stepHeight); if ( t > 0 && t < mxWidth ) { xx = x - offX[i + 1][t]; } else { xx = x; } if ( i + 1 > 0 && i + 1 < mxHeight ) { zz = z - offZ[t][i + 1]; } else { zz = z; } Vector2Set( biPoints[3], xx, zz + stepHeight ); CG_CalcBiLerp( verts, subVerts, biPoints ); float dif = DistanceSquared( subVerts[0], dmgPt ) * timeDecay - random() * 32; // If we decrease dif, we are increasing the impact area, making it more likely to blow out large holes dif -= dmgRadius * dmgRadius; if ( dif > 1 ) { stick = true; time = dif + random() * 200; } else { stick = false; time = 0; } CG_DoGlassQuad( subVerts, biPoints, stick, time, dmgDir ); } } }
/** * @brief Update xviInfection value for each nation, using the XVI overlay. * @note should be executed after all daily event that could change XVI overlay */ void CP_UpdateNationXVIInfection (void) { /* No need to update XVI levels if the overlay didn't change */ if (!xviNationInfectionNeedsUpdate) return; /* width in pixel of the XVI overlay */ int width; /* height in pixel of the XVI overlay */ int height; CP_GetXVIMapDimensions(&width, &height); const float heightPerDegree = height / 180.0f; const float widthPerDegree = width / 360.0f; /* parameter used to normalize nation XVI level. * decrease this factor to increase XVI level per nation */ const float AREA_FACTOR = 650.0f; /* area used to normalized XVI infection level for each nation. * depend on overlay size so that if we change resolution of * overlay it doesn't impact nation XIInfection */ const float normalizingArea = width * height / AREA_FACTOR; /* temporary array to store the XVI levels */ float xviInfection[MAX_NATIONS]; /* Initialize array */ OBJZERO(xviInfection); for (int y = 0; y < height; y++) { int sum[MAX_NATIONS]; const byte* previousNationColor; const nation_t* nation; /* current position (in latitude / longitude) */ vec2_t currentPos; OBJZERO(sum); Vector2Set(currentPos, 180.0f, 90.0f - y / heightPerDegree); previousNationColor = GEO_GetColor(currentPos, MAPTYPE_NATIONS, nullptr); nation = GEO_GetNation(currentPos); for (int x = 0; x < width; x++) { const byte* nationColor; currentPos[0] = 180.0f - x / widthPerDegree; nationColor = GEO_GetColor(currentPos, MAPTYPE_NATIONS, nullptr); if (!VectorCompare(nationColor, previousNationColor)) { previousNationColor = nationColor; nation = GEO_GetNation(currentPos); } if (nation) { const int xviLevel = CP_GetXVILevel(x, y); if (xviLevel > 0) sum[nation->idx] += xviLevel; } } /* divide the total XVI infection by the area of a pixel * because pixel are smaller as you go closer from the pole */ for (int nationIdx = 0; nationIdx < ccs.numNations; nationIdx++) xviInfection[nationIdx] += ((float) sum[nationIdx]) / (cos(torad * currentPos[1]) * normalizingArea); } /* copy the new values of XVI infection level into nation array */ for (int nationIdx = 0; nationIdx < ccs.numNations; nationIdx++) { nation_t* nation = NAT_GetNationByIDX(nationIdx); nation->stats[0].xviInfection = ceil(xviInfection[nation->idx]); } xviNationInfectionNeedsUpdate = false; }