diff --git a/game/reconstructed/btl4gaug.cpp b/game/reconstructed/btl4gaug.cpp index c95c58e..993a781 100644 --- a/game/reconstructed/btl4gaug.cpp +++ b/game/reconstructed/btl4gaug.cpp @@ -1022,11 +1022,213 @@ static void // background fill for the remainder). Uses _DAT_004c452c (0.0) as the floor. // +//########################################################################### +// VertTwoPartBar @004c462c Make / @004c4724 ctor / @004c48e0 BecameActive +// @004c48fc Execute (vtable PTR_FUN_00518c78) // -// @004c462c Make / @004c4724 ctor / @004c48e0 BecameActive / @004c48fc Execute -// -- VertTwoPartBar: identical structure to HorizTwoPartBar but grows -// bottom->top (vtable PTR_FUN_00518c78). Floor constant _DAT_004c4b00 (0.0). +// A vertical two-part fill bar (config keyword "vertBar"). Three Scalar +// connections drive it: value (current), low (warn threshold), high (max). The +// bar grows bottom->top; pixels are value/high and low/high fractions of the bar +// height. Used for the cockpit COOLANT bars (config binds current=CoolantMass, +// warn=CoolantCapacity, max=CoolantCapacity -- so the warn line sits at full and +// the bar simply empties as CoolantMass drops during firing). +//########################################################################### + +MethodDescription + VertTwoPartBar::methodDescription = + { + "vertBar", + VertTwoPartBar::Make, + { + // + // CFG shape (L4GAUGE.CFG:4521): + // vertBar( rate, mode, (w,h), tile.pcc, bg,fill,extra, + // currentAttr, warnAttr, maxAttr ) + // e.g. vertBar(C,ModeAlwaysActive,(31,160),btwarn.pcc,255,255,0, + // HeatSink/CoolantMass, HeatSink/CoolantCapacity, + // HeatSink/CoolantCapacity); + // + { ParameterDescription::typeRate, NULL }, // rate ID + { ParameterDescription::typeModeMask, NULL }, // mode mask + { ParameterDescription::typeVector, NULL }, // (width,height) + { ParameterDescription::typeString, NULL }, // tile bitmap name + { ParameterDescription::typeColor, NULL }, // background colour -> @0x94 + { ParameterDescription::typeColor, NULL }, // fill colour -> @0x98 + { ParameterDescription::typeColor, NULL }, // extra/empty colour-> @0x9C + { ParameterDescription::typeAttribute, NULL }, // current value -> @0xB0 + { ParameterDescription::typeAttribute, NULL }, // warn threshold -> @0xB4 + { ParameterDescription::typeAttribute, NULL }, // max -> @0xB8 + PARAMETER_DESCRIPTION_END + } + }; + // +// @004c462c -- Make. Allocate + construct, then verify the tile bitmap exists +// (== the binary's "VertTwoPartBarNormalized: Missing image" warning path). +// +Logical + VertTwoPartBar::Make( + int display_port_index, + Vector2DOf position, + Entity * /*entity -- unused*/, + GaugeRenderer *gauge_renderer + ) +{ + ParameterDescription *p = methodDescription.parameterList; + + VertTwoPartBar *gauge = (VertTwoPartBar *)operator new(0xbc); // FUN_00402298(0xbc) + if (gauge != NULL) + { + new (gauge) VertTwoPartBar( // FUN_004c4724 + p[0].data.rate, p[1].data.modeMask, + (L4GaugeRenderer *)gauge_renderer, + display_port_index, // graphics_port_number + position.x, position.y, // left, bottom + position.x + p[2].data.vector.x, // right = x + width + position.y + p[2].data.vector.y, // top = y + height + p[3].data.string, // tile bitmap + p[4].data.color, // backgroundColor + p[5].data.color, // fillColor + p[6].data.color, // extraColor + (Scalar *)p[7].data.attributePointer, // current value source + (Scalar *)p[8].data.attributePointer, // warn threshold source + (Scalar *)p[9].data.attributePointer, // max source + "VertTwoPartBar"); + } + + L4Warehouse *warehouse = (L4Warehouse *)gauge_renderer->warehousePointer; + if (warehouse->bitMapBin.Get(p[3].data.string) == NULL) // FUN_00442aec + { + DebugStream << "VertTwoPartBarNormalized: Missing image '" + << p[3].data.string << "'\n"; + return False; + } + warehouse->bitMapBin.Release(p[3].data.string); // FUN_00442c12 + return True; +} + +// +// @004c4724 -- ctor. GraphicGauge base; intern + ref-count the tile bitmap; set +// the graphics-port extent (bottom->top); store the three colours and the bar +// size; wire three GaugeConnectionDirectOf feeds (value/low/high). +// +VertTwoPartBar::VertTwoPartBar( + GaugeRate rate, + ModeMask mode_mask, + L4GaugeRenderer *renderer_in, + int graphics_port_number, + int left, + int bottom, + int right, + int top, + const char *tile_image, + int background_color, + int fill_color, + int extra_color, + Scalar *value_pointer, + Scalar *low_pointer, + Scalar *high_pointer, + const char *identification_string +): + GraphicGauge(rate, mode_mask, renderer_in, 0, // FUN_00444818 (owner_ID 0) + graphics_port_number, identification_string) +{ + // Own a copy of the tile-bitmap name (Make passes the transient interpreter + // scratch buffer) and hold a ref for the gauge's life. + tileImage = new char[strlen(tile_image) + 1]; // @0x90 FUN_004700ac + strcpy(tileImage, tile_image); + L4Warehouse *warehouse = (L4Warehouse *)renderer_in->warehousePointer; + warehouse->bitMapBin.Get(tileImage); // FUN_00442aec (held) + + localView.SetPositionWithinPort(left, bottom, right, top); // this+0x48 vtbl+0x08 + + backgroundColor = background_color; // @0x94 this[0x25] + fillColor = fill_color; // @0x98 this[0x26] + extraColor = extra_color; // @0x9C this[0x27] + width = (right - left) - 1; // @0xA0 this[0x28] + height = top - bottom; // @0xA4 this[0x29] + + AddConnection(new GaugeConnectionDirectOf(0, &value, value_pointer)); // @0xB0 + AddConnection(new GaugeConnectionDirectOf(0, &low, low_pointer)); // @0xB4 + AddConnection(new GaugeConnectionDirectOf(0, &high, high_pointer)); // @0xB8 +} + +// +// @004c486c -- dtor. Release the tile ref (keyed on tileImage, before the free), +// free the interned name; the base chain runs implicitly. +// +VertTwoPartBar::~VertTwoPartBar() +{ + L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer; + warehouse->bitMapBin.Release(tileImage); // FUN_00442c12 + delete[] tileImage; // FUN_004022e8 + tileImage = NULL; +} + +Logical + VertTwoPartBar::TestInstance() const +{ + return GraphicGauge::TestInstance(); +} + +// +// @004c48e0 -- BecameActive: force a full redraw on the first Execute +// (previousFull=0, previousFill=width -- neither can match a real pixel pair). +// +void + VertTwoPartBar::BecameActive() +{ + previousFull = 0; // @0xAC this[0x2B] + previousFill = width; // @0xA8 this[0x2A] +} + +// +// @004c48fc -- Execute. Clamp value to [0,high]; map value and warn to bar +// pixels (half-up round of height*x/high, clamped to [0,height]); if either +// changed, repaint: tile the bitmap over [0,warnPix), fill [warnPix,valPix) with +// fillColor, and clear [valPix,height) with extraColor. (x87 pixel math recovered +// by disassembly @004c4940/@004c4960 -- Ghidra dropped the FPU args.) +// +void + VertTwoPartBar::Execute() +{ + // clamp value to [0, high] (@004c4908 fcomp 0.0 ; @004c4929 fcomp high) + if (value < 0.0f) + value = 0.0f; + else if (value > high) + value = high; + + int warnPix = (int)((Scalar)height * low / high + 0.5f); // warn threshold pixel + int valPix = (int)((Scalar)height * value / high + 0.5f); // current value pixel + if (warnPix < 0) warnPix = 0; else if (warnPix > height) warnPix = height; + if (valPix < 0) valPix = 0; else if (valPix > height) valPix = height; + + if (warnPix != previousFull || valPix != previousFill) + { + L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer; + BitMap *tile = warehouse->bitMapBin.Get(tileImage); // FUN_00442aec + + localView.SetColor(backgroundColor); // vtbl+0x18 + DrawTiledBitmap(&localView, 0, 0, width, warnPix - 1, extraColor, tile); + warehouse->bitMapBin.Release(tileImage); // FUN_00442c12 + + if (warnPix < valPix) // normal fill above the warn line + { + localView.SetColor(fillColor); + localView.MoveToAbsolute(0, warnPix); // vtbl+0x24 + localView.DrawFilledRectangleToAbsolute(width, valPix - 1); // vtbl+0x48 + } + if (valPix < height) // empty region above the value + { + localView.SetColor(extraColor); + localView.MoveToAbsolute(0, valPix); + localView.DrawFilledRectangleToAbsolute(width, height); + } + + previousFull = warnPix; + previousFill = valPix; + } +} // // @004c4b84 ctor / @004c4cac BecameActive / @004c4cc0 Execute diff --git a/game/reconstructed/btl4gaug.hpp b/game/reconstructed/btl4gaug.hpp index f176a2c..0b8ece0 100644 --- a/game/reconstructed/btl4gaug.hpp +++ b/game/reconstructed/btl4gaug.hpp @@ -264,12 +264,15 @@ public GraphicGauge { public: + // Registered in BTL4MethodDescription[] (btl4grnd.cpp) as "vertBar". + static MethodDescription methodDescription; + static Logical Make(int, Vector2DOf, Entity *, GaugeRenderer *); // @004c462c - VertTwoPartBar( // @004c4724 - GaugeRate, ModeMask, L4GaugeRenderer *, int, + VertTwoPartBar( // @004c4724 (ctor arg order = binary param_12..17) + GaugeRate, ModeMask, L4GaugeRenderer *, int graphics_port_number, int left, int bottom, int right, int top, - const char *tile_image, int fill_color, int background_color, - int /*extra_color*/, + const char *tile_image, + int background_color, int fill_color, int extra_color, Scalar *value_pointer, Scalar *low_pointer, Scalar *high_pointer, const char *identification_string); ~VertTwoPartBar(); diff --git a/game/reconstructed/btl4grnd.cpp b/game/reconstructed/btl4grnd.cpp index 2d3b064..a0b3117 100644 --- a/game/reconstructed/btl4grnd.cpp +++ b/game/reconstructed/btl4grnd.cpp @@ -134,6 +134,7 @@ MethodDescription &ColorMapperArmor::methodDescription, // "cmArmor" -- per-zone armor-damage tint &ColorMapperMultiArmor::methodDescription, // "colorMapperMultiArmor" -- worst-of-8-zones tint &ColorMapperCritical::methodDescription, // "cmCrit" -- subsystem-critical-state tint + &VertTwoPartBar::methodDescription, // "vertBar" -- vertical fill bar (coolant/heat) &BTL4ChainToPrevious };