|
1 | | -/* |
| 1 | +/* |
2 | 2 | ** Command & Conquer Generals Zero Hour(tm) |
3 | 3 | ** Copyright 2025 Electronic Arts Inc. |
4 | 4 | ** |
@@ -492,6 +492,13 @@ void BaseHeightMapRenderObjClass::ReAcquireResources(void) |
492 | 492 | } |
493 | 493 | } |
494 | 494 |
|
| 495 | +// -------- |
| 496 | +static float invLerp(float a, float b, float v) |
| 497 | +{ |
| 498 | + if (a == b) return 0.0f; // avoid divide by zero |
| 499 | + return (v - a) / (b - a); |
| 500 | +} |
| 501 | + |
495 | 502 | //============================================================================= |
496 | 503 | // BaseHeightMapRenderObjClass::doTheLight |
497 | 504 | //============================================================================= |
@@ -591,6 +598,99 @@ void BaseHeightMapRenderObjClass::doTheLight(VERTEX_FORMAT *vb, Vector3*light, V |
591 | 598 | if (shadeB > 1.0) shadeB = 1.0; |
592 | 599 | if(shadeB < 0.0f) shadeB = 0.0f; |
593 | 600 |
|
| 601 | + // --------------------------------------------- |
| 602 | + // Height based ambient light factor (for water) |
| 603 | + // --------------------------------------------- |
| 604 | + if (TheGlobalData && |
| 605 | + TheGlobalData->m_terrainHeightAmbientLightHeightStart > 0 && |
| 606 | + (TheGlobalData->m_terrainHeightAmbientLightHeight1 >= 0 || TheGlobalData->m_terrainHeightAmbientLightHeight2 >= 0) && |
| 607 | + vb->z <= TheGlobalData->m_terrainHeightAmbientLightHeightStart |
| 608 | + ) { |
| 609 | + Real col1R, col1G, col1B, col2R, col2G, col2B; |
| 610 | + //Real factor1 = 0.0; |
| 611 | + //Real factor2 = 0.0; |
| 612 | + Real height1 = -1; |
| 613 | + Real height2 = -1; |
| 614 | + |
| 615 | + Real colR; |
| 616 | + Real colG; |
| 617 | + Real colB; |
| 618 | + |
| 619 | + // case 1: only one color |
| 620 | + if (TheGlobalData->m_terrainHeightAmbientLightHeight1 <= 0) |
| 621 | + { |
| 622 | + col1R = TheGlobalData->m_terrainHeightAmbientLightColor2.red; |
| 623 | + col1G = TheGlobalData->m_terrainHeightAmbientLightColor2.green; |
| 624 | + col1B = TheGlobalData->m_terrainHeightAmbientLightColor2.blue; |
| 625 | + height1 = TheGlobalData->m_terrainHeightAmbientLightHeight2; |
| 626 | + } |
| 627 | + else if (TheGlobalData->m_terrainHeightAmbientLightHeight2 <= 0) { |
| 628 | + col1R = TheGlobalData->m_terrainHeightAmbientLightColor1.red; |
| 629 | + col1G = TheGlobalData->m_terrainHeightAmbientLightColor1.green; |
| 630 | + col1B = TheGlobalData->m_terrainHeightAmbientLightColor1.blue; |
| 631 | + height1 = TheGlobalData->m_terrainHeightAmbientLightHeight1; |
| 632 | + } |
| 633 | + else |
| 634 | + { // case 2: both colors |
| 635 | + |
| 636 | + col1R = TheGlobalData->m_terrainHeightAmbientLightColor1.red; |
| 637 | + col1G = TheGlobalData->m_terrainHeightAmbientLightColor1.green; |
| 638 | + col1B = TheGlobalData->m_terrainHeightAmbientLightColor1.blue; |
| 639 | + col2R = TheGlobalData->m_terrainHeightAmbientLightColor2.red; |
| 640 | + col2G = TheGlobalData->m_terrainHeightAmbientLightColor2.green; |
| 641 | + col2B = TheGlobalData->m_terrainHeightAmbientLightColor2.blue; |
| 642 | + height1 = TheGlobalData->m_terrainHeightAmbientLightHeight1; |
| 643 | + height2 = TheGlobalData->m_terrainHeightAmbientLightHeight2; |
| 644 | + } |
| 645 | + |
| 646 | + bool multiply = !TheGlobalData->m_terrainHeightAmbientLightAdditive; |
| 647 | + Real base; |
| 648 | + if (multiply) |
| 649 | + base = 1.0; |
| 650 | + else |
| 651 | + base = 0.0; |
| 652 | + |
| 653 | + if (vb->z > height1) { |
| 654 | + Real t = WWMath::Clamp(invLerp(TheGlobalData->m_terrainHeightAmbientLightHeightStart, height1, vb->z)); |
| 655 | + colR = col1R * t + (1.0 - t) * base; |
| 656 | + colG = col1G * t + (1.0 - t) * base; |
| 657 | + colB = col1B * t + (1.0 - t) * base; |
| 658 | + } |
| 659 | + |
| 660 | + // Between height1 and height2 |
| 661 | + else if (height2 > -1 && vb->z > height2) |
| 662 | + { |
| 663 | + Real t = WWMath::Clamp(invLerp(height1, height2, vb->z)); |
| 664 | + Real factor1 = 1.0f - t; // 1 → 0 |
| 665 | + Real factor2 = t; // 0 → 1 |
| 666 | + |
| 667 | + colR = col1R * factor1 + col2R * factor2; |
| 668 | + colG = col1G * factor1 + col2G * factor2; |
| 669 | + colB = col1B * factor1 + col2B * factor2; |
| 670 | + } |
| 671 | + // below |
| 672 | + else { |
| 673 | + colR = col2R; |
| 674 | + colG = col2G; |
| 675 | + colB = col2B; |
| 676 | + } |
| 677 | + |
| 678 | + if (multiply) { |
| 679 | + shadeR *= colR; |
| 680 | + shadeG *= colG; |
| 681 | + shadeB *= colB; |
| 682 | + } |
| 683 | + else { |
| 684 | + shadeR = WWMath::Clamp(shadeR + colR); |
| 685 | + shadeG = WWMath::Clamp(shadeG + colG); |
| 686 | + shadeB = WWMath::Clamp(shadeB + colB); |
| 687 | + } |
| 688 | + } |
| 689 | + // --------------------------------------------- |
| 690 | + |
| 691 | + |
| 692 | + |
| 693 | + // Old, inactive code |
594 | 694 | if (m_useDepthFade && vb->z <= TheGlobalData->m_waterPositionZ) |
595 | 695 | { //height is below water level |
596 | 696 | //reduce lighting values based on light fall off as it travels through water. |
|
0 commit comments