From: Rudolf Polzer Date: Sat, 18 Jun 2011 16:59:33 +0000 (+0200) Subject: an all-new waypointsprite drawing system that allows sprites to be translated X-Git-Tag: xonotic-v0.5.0~199^2~14^2~2^2~8 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=cc2682a46718d8e67edd197281bdcbd09bed26b1;p=xonotic%2Fxonotic-data.pk3dir.git an all-new waypointsprite drawing system that allows sprites to be translated --- diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index 76371bf0e..12eb4b655 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -1238,6 +1238,7 @@ set g_waypointsprite_deadlifetime 1 set g_waypointsprite_limitedrange 5120 set g_waypointsprite_stuffbinds 0 seta g_waypointsprite_scale 1 +seta g_waypointsprite_fontsize 12 seta g_waypointsprite_alpha 1 "This allows the client to control transparency of the waypoint" seta g_waypointsprite_edgefadealpha 0.5 "alpha multiplier near the edge" seta g_waypointsprite_edgefadescale 1 "scale multiplier near the edge" diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh index bf9924a92..67b6d4008 100644 --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@ -137,6 +137,7 @@ float autocvar_g_waypointsprite_minalpha; float autocvar_g_waypointsprite_minscale; float autocvar_g_waypointsprite_normdistance; var float autocvar_g_waypointsprite_scale = 1; +var float autocvar_g_waypointsprite_fontsize = 12; float autocvar_g_waypointsprite_timealphaexponent; var float autocvar_hud_colorflash_alpha = 0.5; float autocvar_hud_configure_bg_minalpha; diff --git a/qcsrc/client/waypointsprites.qc b/qcsrc/client/waypointsprites.qc index bcd8c433e..26b05d651 100644 --- a/qcsrc/client/waypointsprites.qc +++ b/qcsrc/client/waypointsprites.qc @@ -6,6 +6,7 @@ float waypointsprite_minalpha; float waypointsprite_distancealphaexponent; float waypointsprite_timealphaexponent; float waypointsprite_scale; +float waypointsprite_fontsize; float waypointsprite_edgefadealpha; float waypointsprite_edgefadescale; float waypointsprite_edgefadedistance; @@ -32,14 +33,13 @@ float waypointsprite_alpha; .float build_starthealth; .float build_finished; -vector SPRITE_SIZE = '288 36 0'; -vector SPRITE_HOTSPOT = '144 36 0'; float SPRITE_HEALTHBAR_WIDTH = 144; float SPRITE_HEALTHBAR_HEIGHT = 9; float SPRITE_HEALTHBAR_MARGIN = 6; float SPRITE_HEALTHBAR_BORDER = 2; float SPRITE_HEALTHBAR_BORDERALPHA = 1; float SPRITE_HEALTHBAR_HEALTHALPHA = 0.5; +float SPRITE_ARROW_SCALE = 1.0; void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f) { @@ -106,6 +106,240 @@ void drawhealthbar(vector org, float rot, float h, vector sz, vector hotspot, fl drawquad(o + ri * (border + align * ((1 - h) * width)), ri * width * h, up * height, "", hrgb, ha, f); } +// returns location of sprite text +vector drawspritearrow(vector o, float ang, vector rgb, float a, float t) +{ + R_BeginPolygon("", DRAWFLAG_NORMAL); + R_PolygonVertex(o + rotate('-11.5 9.5 0'*t, ang), '0 0 0', '0 0 0', a); + R_PolygonVertex(o + rotate('11.5 9.5 0'*t, ang), '0 0 0', '0 0 0', a); + R_PolygonVertex(o + rotate('0 -2 0'*t, ang), '0 0 0', '0 0 0', a); + R_EndPolygon(); + R_BeginPolygon("", DRAWFLAG_NORMAL); + R_PolygonVertex(o + rotate('-5.5 9.5 0'*t, ang), '0 0 0', '0 0 0', a); + R_PolygonVertex(o + rotate('-5.5 17.5 0'*t, ang), '0 0 0', '0 0 0', a); + R_PolygonVertex(o + rotate('5.5 17.5 0'*t, ang), '0 0 0', '0 0 0', a); + R_PolygonVertex(o + rotate('5.5 9.5 0'*t, ang), '0 0 0', '0 0 0', a); + R_EndPolygon(); + + R_BeginPolygon("", DRAWFLAG_NORMAL); + R_PolygonVertex(o + rotate('-8 8 0'*t, ang), '0 0 0', rgb, a); + R_PolygonVertex(o + rotate('8 8 0'*t, ang), '0 0 0', rgb, a); + R_PolygonVertex(o + rotate('0 0 0'*t, ang), '0 0 0', rgb, a); + R_EndPolygon(); + R_BeginPolygon("", DRAWFLAG_NORMAL); + R_PolygonVertex(o + rotate('-4 8 0'*t, ang), '0 0 0', rgb, a); + R_PolygonVertex(o + rotate('-4 16 0'*t, ang), '0 0 0', rgb, a); + R_PolygonVertex(o + rotate('4 16 0'*t, ang), '0 0 0', rgb, a); + R_PolygonVertex(o + rotate('4 8 0'*t, ang), '0 0 0', rgb, a); + R_EndPolygon(); + + return + o + rotate('0 20 0'*t, ang); +} + +// returns location of sprite healthbar +vector drawspritetext(vector o, float ang, float minwidth, vector rgb, float a, vector fontsize, string s) +{ + float algnx, algny; + float sw, w, h; + float aspect, sa, ca; + + sw = stringwidth(s, FALSE, fontsize); + if(sw > minwidth) + w = sw; + else + w = minwidth; + h = fontsize_y; + + // how do corners work? + aspect = vid_conwidth / vid_conheight; + sa = sin(ang); + ca = cos(ang) * aspect; + if(fabs(sa) > fabs(ca)) + { + algnx = (sa < 0); + algny = 0.5 - 0.5 * ca / fabs(sa); + } + else + { + algnx = 0.5 - 0.5 * sa / fabs(ca); + algny = (ca < 0); + } + + // align + o_x -= w * algnx; + o_y -= h * algny; + + // we want to be onscreen + if(o_x < 0) + o_x = 0; + if(o_y < 0) + o_y = 0; + if(o_x > vid_conwidth - w) + o_x = vid_conwidth - w; + if(o_y > vid_conheight - h) + o_x = vid_conheight - h; + + o_x += 0.5 * (w - sw); + + drawstring(o, s, fontsize, rgb, a, DRAWFLAG_NORMAL); + + o_x += 0.5 * sw; + o_y += 0.5 * h; + + return o; +} + +float spritelookupblinkvalue(string s) +{ + switch(s) + { + case "ons-cp-atck-neut": return 2; + case "ons-cp-atck-red": return 2; + case "ons-cp-atck-blue": return 2; + case "ons-cp-dfnd-red": return 0.5; + case "ons-cp-dfnd-blue": return 0.5; + case "item-invis": return 2; + case "item-extralife": return 2; + case "item-speed": return 2; + case "item-strength": return 2; + case "item-shueld": return 2; + case "item-fuelregen": return 2; + case "item-jetpack": return 2; + default: return 1; + } +} +string spritelookuptext(string s) +{ + switch(s) + { + case "as-push": return _("Push"); + case "as-destroy": return _("Destroy"); + case "as-defend": return _("Defend"); + case "bluebase": return _("Blue base"); + case "danger": return _("DANGER"); + case "flagcarrier": return _("Flag carrier"); + case "flagdropped": return _("Dropped flag"); + case "helpme": return _("Help me!"); + case "here": return _("Here"); + case "key-dropped": return _("Dropped key"); + case "keycarrier-blue": return _("Key carrier"); + case "keycarrier-finish": return _("Run here"); + case "keycarrier-friend": return _("Key carrier"); + case "keycarrier-pink": return _("Key carrier"); + case "keycarrier-red": return _("Key carrier"); + case "keycarrier-yellow": return _("Key carrier"); + case "redbase": return _("Red base"); + case "waypoint": return _("Waypoint"); + case "ons-gen-red": return _("Generator"); + case "ons-gen-blue": return _("Generator"); + case "ons-gen-shielded": return _("Generator"); + case "ons-cp-neut": return _("Control point"); + case "ons-cp-red": return _("Control point"); + case "ons-cp-blue": return _("Control point"); + case "ons-cp-atck-neut": return _("Control point"); + case "ons-cp-atck-red": return _("Control point"); + case "ons-cp-atck-blue": return _("Control point"); + case "ons-cp-dfnd-red": return _("Control point"); + case "ons-cp-dfnd-blue": return _("Control point"); + case "race-checkpoint": return _("Checkpoint"); + case "race-finish": return _("Finish"); + case "race-start": return _("Start"); + case "nb-ball": return _("Ball"); + case "ka-ball": return _("Ball"); + case "ka-ballcarrier": return _("Ball carrier"); + case "wpn-laser": return _("Laser"); + case "wpn-shotgun": return _("Shotgun"); + case "wpn-uzi": return _("Machine Gun"); + case "wpn-gl": return _("Mortar"); + case "wpn-electro": return _("Electro"); + case "wpn-crylink": return _("Crylink"); + case "wpn-nex": return _("Nex"); + case "wpn-hagar": return _("Hagar"); + case "wpn-rl": return _("Rocket Launcher"); + case "wpn-porto": return _("Port-O-Launch"); + case "wpn-minstanex": return _("Minstanex"); + case "wpn-hookgun": return _("Hook"); + case "wpn-fireball": return _("Fireball"); + case "wpn-hlac": return _("HLAC"); + case "wpn-campingrifle": return _("Rifle"); + case "wpn-minelayer": return _("Mine Layer"); + case "dom-neut": return _("Control point"); + case "dom-red": return _("Control point"); + case "dom-blue": return _("Control point"); + case "dom-yellow": return _("Control point"); + case "dom-pink": return _("Control point"); + case "item-invis": return _("Invisibility"); + case "item-extralife": return _("Extra life"); + case "item-speed": return _("Speed"); + case "item-strength": return _("Strength"); + case "item-shield": return _("Shield"); + case "item-fuelregen": return _("Fuel regen"); + case "item-jetpack": return _("Jet Pack"); + case "freezetag_frozen": return _("Frozen!"); + case "tagged-target": return _("Tagged"); + default: return s; + } +} + +vector fixrgbexcess_move(vector rgb, vector src, vector dst) +{ + vector yvec = '0.299 0.587 0.114'; + return rgb + dst * ((src * yvec) / (dst * yvec)) * ((rgb - '1 1 1') * src); +} +vector fixrgbexcess(vector rgb) +{ + if(rgb_x > 1) + { + rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 1'); + if(rgb_y > 1) + { + rgb = fixrgbexcess_move(rgb, '0 1 0', '0 0 1'); + if(rgb_z > 1) + rgb_z = 1; + } + else if(rgb_z > 1) + { + rgb = fixrgbexcess_move(rgb, '0 0 1', '0 1 0'); + if(rgb_y > 1) + rgb_y = 1; + } + } + else if(rgb_y > 1) + { + rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 1'); + if(rgb_x > 1) + { + rgb = fixrgbexcess_move(rgb, '1 0 0', '0 0 1'); + if(rgb_z > 1) + rgb_z = 1; + } + else if(rgb_z > 1) + { + rgb = fixrgbexcess_move(rgb, '0 0 1', '1 0 0'); + if(rgb_x > 1) + rgb_x = 1; + } + } + else if(rgb_z > 1) + { + rgb = fixrgbexcess_move(rgb, '0 0 1', '1 1 0'); + if(rgb_x > 1) + { + rgb = fixrgbexcess_move(rgb, '1 0 0', '0 1 0'); + if(rgb_y > 1) + rgb_y = 1; + } + else if(rgb_y > 1) + { + rgb = fixrgbexcess_move(rgb, '0 1 0', '1 0 0'); + if(rgb_x > 1) + rgb_x = 1; + } + } + return rgb; +} + void Draw_WaypointSprite() { string spriteimage; @@ -173,34 +407,37 @@ void Draw_WaypointSprite() else if(self.maxdistance > 0) a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha; + vector rgb; + rgb = self.teamradar_color; + + if(time - floor(time) > 0.5) + a *= spritelookupblinkvalue(spriteimage); + + if(a > 1) + { + rgb *= a; + a = 1; + } + if(a <= 0) return; - - // draw the sprite image + + rgb = fixrgbexcess(rgb); + vector o; - float rot; - o = project_3d_to_2d(self.origin); - rot = 0; + float ang; + o = project_3d_to_2d(self.origin); if(o_z < 0 || o_x < 0 || o_y < 0 || o_x > vid_conwidth || o_y > vid_conheight) { // scale it to be just in view vector d; float f1, f2; - // get the waypoint angle vector - /* - d_x = view_right * (self.origin - view_origin) * vid_conwidth / vid_width; - d_y = -view_up * (self.origin - view_origin) * vid_conheight / (vid_height * vid_pixelheight); - d_z = 0; - */ - d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight; - - /* - if(autocvar_v_flipped) - d_x = -d_x; - */ + ang = atan2(-d_x, -d_y); + if(o_z < 0) + ang += M_PI; f1 = d_x / vid_conwidth; f2 = d_y / vid_conheight; @@ -211,13 +448,11 @@ void Draw_WaypointSprite() { // RIGHT edge d = d * (0.5 / f1); - rot = 3; } else { // LEFT edge d = d * (-0.5 / f1); - rot = 1; } } else @@ -226,32 +461,28 @@ void Draw_WaypointSprite() { // BOTTOM edge d = d * (0.5 / f2); - rot = 0; } else { // TOP edge d = d * (-0.5 / f2); - rot = 2; } } o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight; } - o_z = 0; - - float vidscale; - vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height); - - t = stof(db_get(tempdb, strcat("/spriteframes/", spriteimage))); - if(t == 0) - spriteimage = strcat("models/sprites/", spriteimage); else - spriteimage = strcat("models/sprites/", spriteimage, "_frame", ftos(mod(floor((max(0, time - self.spawntime)) * 2), t))); + { + ang = M_PI; + } + o_z = 0; float edgedistance_min, crosshairdistance; edgedistance_min = min4(o_y, o_x,vid_conwidth - o_x, vid_conheight - o_y); + float vidscale; + vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height); + crosshairdistance = sqrt( pow(o_x - vid_conwidth/2, 2) + pow(o_y - vid_conheight/2, 2) ); t = waypointsprite_scale * vidscale; @@ -269,7 +500,6 @@ void Draw_WaypointSprite() a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1))); t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1))); } - drawrotpic(o, rot * 90 * DEG2RAD, spriteimage, SPRITE_SIZE * t, SPRITE_HOTSPOT * t, '1 1 1', a, DRAWFLAG_MIPMAP); if(self.build_finished) { @@ -286,14 +516,46 @@ void Draw_WaypointSprite() self.health = -1; } + o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t); + + string txt; + txt = spritelookuptext(spriteimage); + txt = strtoupper(txt); + if(self.health >= 0) { - float align; + o = drawspritetext(o, ang, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt); + + float align, marg; if(self.build_finished) align = 0.5; else align = 0; - drawhealthbar(o, rot * 90 * DEG2RAD, self.health, SPRITE_SIZE * t, SPRITE_HOTSPOT * t, SPRITE_HEALTHBAR_WIDTH * t, SPRITE_HEALTHBAR_HEIGHT * t, SPRITE_HEALTHBAR_MARGIN * t, SPRITE_HEALTHBAR_BORDER * t, align, self.teamradar_color, a * SPRITE_HEALTHBAR_BORDERALPHA, self.teamradar_color, a * SPRITE_HEALTHBAR_HEALTHALPHA, DRAWFLAG_NORMAL); + if(cos(ang) > 0) + marg = -(SPRITE_HEALTHBAR_MARGIN + SPRITE_HEALTHBAR_HEIGHT + 2 * SPRITE_HEALTHBAR_BORDER) * t - 0.5 * waypointsprite_fontsize; + else + marg = SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize; + drawhealthbar( + o, + 0, + self.health, + '0 0 0', + '0 0 0', + SPRITE_HEALTHBAR_WIDTH * t, + SPRITE_HEALTHBAR_HEIGHT * t, + marg, + SPRITE_HEALTHBAR_BORDER * t, + align, + rgb, + a * SPRITE_HEALTHBAR_BORDERALPHA, + rgb, + a * SPRITE_HEALTHBAR_HEALTHALPHA, + DRAWFLAG_NORMAL + ); + } + else + { + o = drawspritetext(o, ang, 0, rgb, a, waypointsprite_fontsize * '1 1 0', txt); } } @@ -438,6 +700,7 @@ void WaypointSprite_Load() waypointsprite_distancealphaexponent = autocvar_g_waypointsprite_distancealphaexponent; waypointsprite_timealphaexponent = autocvar_g_waypointsprite_timealphaexponent; waypointsprite_scale = autocvar_g_waypointsprite_scale; + waypointsprite_fontsize = autocvar_g_waypointsprite_fontsize; waypointsprite_edgefadealpha = autocvar_g_waypointsprite_edgefadealpha; waypointsprite_edgefadescale = autocvar_g_waypointsprite_edgefadescale; waypointsprite_edgefadedistance = autocvar_g_waypointsprite_edgefadedistance;