Files
LCE-Revelations/Minecraft.Client/Gui.cpp
Revela b28c0026af detailed summary of every changed file:
---
  Minecraft.Client/ClientConnection.cpp

  Purpose: Propagate hardcore flag through network level creation

  - handleLogin() (2 sites): Changed MultiPlayerLevel constructor calls from hardcoded false for the
  hardcore parameter to packet->m_isHardcore, so the client-side level correctly knows it's hardcore
  when joining a server.
  - handleRespawn(): Same change - when creating a new dimension level on respawn, uses
  packet->m_isHardcore instead of querying minecraft->level->getLevelData()->isHardcore() (which could
   be stale/wrong).

  ---
  Minecraft.Client/Common/App_Defines.h

  Purpose: Define bitmask for hardcore host option

  - Added GAME_HOST_OPTION_BITMASK_HARDCORE (0x40000000) - a new bit in the host options bitfield to
  store whether the game is hardcore.

  ---
  Minecraft.Client/Common/App_enums.h

  Purpose: Add hardcore enum value

  - Added eGameHostOption_Hardcore to the eGameHostOption enum so code can get/set the hardcore flag
  via SetGameHostOption/GetGameHostOption.

  ---
  Minecraft.Client/Common/Consoles_App.cpp

  Purpose: Implement hardcore get/set in host options bitfield

  - SetGameHostOption(): Added case eGameHostOption_Hardcore - sets or clears the
  GAME_HOST_OPTION_BITMASK_HARDCORE bit.
  - GetGameHostOption(): Added case eGameHostOption_Hardcore - returns 1 if the hardcore bit is set, 0
   otherwise.

  ---
  Minecraft.Client/Common/Consoles_App.h

  Purpose: Store save folder name for hardcore world deletion

  - Added SetCurrentSaveFolderName() and GetCurrentSaveFolderName() public methods.
  - Added wstring m_currentSaveFolderName private member - stores the save folder name so the hardcore
   death handler can find and delete the world.

  ---
  Minecraft.Client/Common/UI/IUIScene_PauseMenu.cpp

  Purpose: Delete hardcore world's save data on exit

  - Added Win64_DeleteSaveDirectory() - a recursive directory deletion helper (Windows64 only).
  - In _ExitWorld(): Before the server is torn down, captures whether this is a hardcore death exit
  (getDeleteWorldOnExit()). Tries 3 sources for the save folder name: app storage, StorageManager, and
   MinecraftServer.
  - After the server fully stops, if shouldDeleteHardcoreWorld is true, deletes the entire
  Windows64\GameHDD\<savefolder> directory.

  ---
  Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.cpp

  Purpose: Hardcore difficulty slider in Create World menu

  - Added file-scope s_bHardcore flag to track when the slider is at position 4 (Hardcore).
  - Constructor: Extended difficulty slider range from 0-3 to 0-4, resets s_bHardcore to false.
  - handleSliderMove(): When slider value >= 4, sets s_bHardcore = true, stores actual difficulty as 3
   (Hard), and displays "Hardcore" label. Otherwise behaves normally.
  - CreateGame(): Clears the save folder name (new world), and sets eGameHostOption_Hardcore based on
  s_bHardcore.
  - Minor: Changed RequestErrorMessage to RequestAlertMessage for a content restriction dialog.

  ---
  Minecraft.Client/Common/UI/UIScene_DeathMenu.cpp

  Purpose: Hardcore death screen behavior (Iggy UI)

  - Constructor: Checks if current level is hardcore. If so, shows IDS_HARDCORE_DEATH_MESSAGE on the
  respawn button and hides it. Otherwise shows normal "Respawn" button.
  - handlePress() - Respawn: Added safeguard - if hardcore, blocks respawn entirely.
  - handlePress() - Exit Game: If hardcore and host, skips save dialog, disables save-on-exit, enables
   delete-world-on-exit, and triggers immediate world exit.

  ---
  Minecraft.Client/Common/UI/UIScene_LoadMenu.cpp

  Purpose: Show "Difficulty: Hardcore" in Load World menu + persist hardcore through game launch

  - Static array: Expanded m_iDifficultyTitleSettingA from 4 to 5 entries, added IDS_GAMEMODE_HARDCORE
   at index 4.
  - Constructor: Initializes m_bHardcore = false. In Windows64 block: sets up thumbnail name from save
   details, and reads isHardcore from params->saveDetails. If hardcore, immediately initializes the
  difficulty slider to show "Hardcore" locked at position 4.
  - tick(): When host options are read (bHostOptionsRead block), also reads the hardcore flag and
  re-initializes the slider if needed (for console path).
  - handleSliderMove(): If m_bHardcore, locks the slider at position 4 (prevents changing difficulty).
  - StartGameFromSave(): Stores the save folder name in app for later hardcore deletion. Sets
  eGameHostOption_Hardcore from m_bHardcore.

  ---
  Minecraft.Client/Common/UI/UIScene_LoadMenu.h

  Purpose: Declare hardcore member

  - Expanded m_iDifficultyTitleSettingA from [4] to [5].
  - Added bool m_bHardcore private member.

  ---
  Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp

  Purpose: Read hardcore flag from level.dat when building the save list

  - ReadLevelNameFromSaveFile(): Added optional bool *outHardcore parameter. Inside the NBT Data
  compound tag parsing, if outHardcore is non-null, reads dataTag->getBoolean(L"hardcore").
  - Save enumeration block (Windows64): Passes &saveHardcore to ReadLevelNameFromSaveFile and stores
  the result in m_saveDetails[i].isHardcore.

  ---
  Minecraft.Client/Common/UI/UIStructs.h

  Purpose: Add isHardcore to save list details struct

  - Added bool isHardcore field to _SaveListDetails struct.
  - Initialized to false in the constructor.

  ---
  Minecraft.Client/Common/XUI/XUI_Death.cpp

  Purpose: Hardcore death screen behavior (XUI/Xbox UI)

  - Mirror of the Iggy UIScene_DeathMenu.cpp changes but for the XUI rendering path.
  - OnInit(): Checks isHardcore(), hides respawn button and shows death message if true.
  - OnNotifyPressEx() - Exit Game: If hardcore and host, skips save, flags world for deletion, exits
  immediately.
  - OnNotifyPressEx() - Respawn: Safeguard to block respawn in hardcore.

  ---
  Minecraft.Client/Gui.cpp

  Purpose: Syntax fix

  - Fixed lines.push_back(L"" → lines.push_back(L"") - missing closing quote/paren in debug terrain
  feature display.

  ---
  Minecraft.Client/MinecraftServer.cpp

  Purpose: Server-side hardcore support

  - Constructor: Initializes m_deleteWorldOnExit = false.
  - loadLevel(): Captures the save folder name from StorageManager into m_saveFolderName for later use
   in hardcore world deletion.
  - isHardcore(): Changed from always returning false to returning
  app.GetGameHostOption(eGameHostOption_Hardcore) > 0 - this is the key change that makes the server
  actually report hardcore mode.

  ---
  Minecraft.Client/MinecraftServer.h

  Purpose: Declare hardcore-related members

  - Added bool m_deleteWorldOnExit and wstring m_saveFolderName private members.
  - Added setDeleteWorldOnExit(), getDeleteWorldOnExit(), and getSaveFolderName() public methods.

  ---
  Minecraft.Client/PlayerConnection.h

  Purpose: Thread-safety fix for kicked flag

  - Changed m_bWasKicked from bool to std::atomic<bool> (initialized with {false}).
  - Changed setWasKicked()/getWasKicked() to use .store()/.load() - fixes a race condition where the
  kicked flag is set on one thread and read on another.

  ---
  Minecraft.Client/PlayerList.cpp

  Purpose: Hardcore multiplayer - ban, respawn as Adventure, thread-safe bans

  - Constructor/Destructor: Added InitializeCriticalSection/DeleteCriticalSection for m_banCS.
  - placeNewPlayer(): Passes isHardcore() flag to the LoginPacket constructor so clients joining know
  it's hardcore.
  - respawn(): After respawn in hardcore, forces the player into Adventure mode (spectate-like: can
  look around but not interact). Sends GameEventPacket to sync client.
  - respawn() and toggleDimension() (2 sites): Pass isHardcore() to RespawnPacket constructor.
  - isXuidBanned(): Wrapped m_bannedXuids iteration with EnterCriticalSection/LeaveCriticalSection for
   thread safety.
  - banXuid() (new): Thread-safe method to add a player's XUID to the ban list - used when a player
  dies in hardcore multiplayer.

  ---
  Minecraft.Client/PlayerList.h

  Purpose: Declare ban-related additions

  - Added CRITICAL_SECTION m_banCS to protect m_bannedXuids.
  - Added void banXuid(PlayerUID xuid) public method.

  ---
  Minecraft.Client/SelectWorldScreen.cpp

  Purpose: Show [Hardcore] badge in Java-style world list

  - In renderItem(): If levelSummary->isHardcore(), appends  [Hardcore] to the world name display.

  ---
  Minecraft.Client/ServerPlayer.cpp

  Purpose: Hardcore death behavior on server

  - die(): If the level is hardcore, switches the dead player to Adventure mode (so they can't
  interact if somehow respawned).
  - Minor: Two comment lines changed // → /// (no functional change).

  ---
  Minecraft.Client/Windows64Media/strings.h

  Purpose: String IDs for hardcore UI text

  - Added 8 new string IDs (2286-2293): IDS_GAMEMODE_HARDCORE, IDS_HARDCORE, IDS_HARDCORE_TOOLTIP,
  IDS_HARDCORE_WARNING_TITLE, IDS_HARDCORE_WARNING_TEXT, IDS_HARDCORE_DEATH_MESSAGE,
  IDS_LABEL_HARDCORE, IDS_GAMEOPTION_HARDCORE.

  ---
  Minecraft.World/ConsoleSaveFileOriginal.cpp

  Purpose: Capture save folder name after first save (for new worlds)

  - SaveSaveDataCallback() (Windows64 only): After a successful save, if the app doesn't yet know the
  save folder name, attempts to capture it via StorageManager or by scanning Windows64\GameHDD\ for
  the newest folder. This handles the case where a newly-created hardcore world hasn't been saved yet
  when the folder name is needed.

  ---
  Minecraft.World/DisconnectPacket.h

  Purpose: Hardcore disconnect reason

  - Added eDisconnect_HardcoreDeath to the disconnect reason enum - used when kicking a player who
  died in hardcore multiplayer.

  ---
  Minecraft.World/LoginPacket.cpp & LoginPacket.h

  Purpose: Serialize hardcore flag in login packet

  - Added bool m_isHardcore member, initialized to false in both constructors.
  - Server→Client constructor now accepts bool isHardcore = false parameter.
  - read(): Reads m_isHardcore from the stream.
  - write(): Writes m_isHardcore to the stream.
  - getEstimatedSize(): Added sizeof(bool) for the new field.

  ---
  Minecraft.World/RespawnPacket.cpp & RespawnPacket.h

  Purpose: Serialize hardcore flag in respawn packet

  - Added bool m_isHardcore member, initialized to false.
  - Constructor now accepts bool isHardcore = false parameter.
  - read()/write(): Serialize m_isHardcore via readBoolean()/writeBoolean().
  - getEstimatedSize(): Changed from 13 to 14 bytes to account for the new boolean.
2026-03-13 06:56:46 -05:00

1712 lines
55 KiB
C++

#include "stdafx.h"
#include "Gui.h"
#include "ItemRenderer.h"
#include "GameRenderer.h"
#include "Options.h"
#include "MultiplayerLocalPlayer.h"
#include "Textures.h"
#include "TextureAtlas.h"
#include "GameMode.h"
#include "Lighting.h"
#include "ChatScreen.h"
#include "MultiPlayerLevel.h"
#include "..\Minecraft.World\JavaMath.h"
#include "..\Minecraft.World\net.minecraft.world.entity.player.h"
#include "..\Minecraft.World\net.minecraft.world.effect.h"
#include "..\Minecraft.World\net.minecraft.world.food.h"
#include "..\Minecraft.World\net.minecraft.world.item.h"
#include "..\Minecraft.World\net.minecraft.world.level.h"
#include "..\Minecraft.World\LevelData.h"
#include "..\Minecraft.World\net.minecraft.world.level.tile.h"
#include "..\Minecraft.World\System.h"
#include "..\Minecraft.World\Language.h"
#include "EntityRenderDispatcher.h"
#include "..\Minecraft.World\Dimension.h"
#include "..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h"
#include "EnderDragonRenderer.h"
#include "..\Minecraft.World\net.minecraft.h"
#include "..\Minecraft.World\net.minecraft.world.h"
#include "..\Minecraft.World\LevelChunk.h"
#include "..\Minecraft.World\Biome.h"
#include <Common/UI/UI.h>
ResourceLocation Gui::PUMPKIN_BLUR_LOCATION = ResourceLocation(TN__BLUR__MISC_PUMPKINBLUR);
#define RENDER_HUD 0
//#ifndef _XBOX
//#undef RENDER_HUD
//#define RENDER_HUD 1
//#endif
float Gui::currentGuiBlendFactor = 1.0f; // 4J added
float Gui::currentGuiScaleFactor = 1.0f; // 4J added
ItemRenderer *Gui::itemRenderer = new ItemRenderer();
Gui::Gui(Minecraft *minecraft)
{
// 4J - initialisers added
random = new Random();
tickCount = 0;
overlayMessageTime = 0;
animateOverlayMessageColor = false;
progress = 0.0f;
tbr = 1.0f;
fAlphaIncrementPerCent=255.0f/100.0f;
this->minecraft = minecraft;
lastTickA = 0.0f;
}
void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
{
// 4J Stu - I have copied this code for XUI_BaseScene. If/when it gets changed it should be broken out
// 4J - altered to force full screen mode to 3X scaling, and any split screen modes to 2X scaling. This is so that the further scaling by 0.5 that
// happens in split screen modes results in a final scaling of 1 rather than 1.5.
if (minecraft->player == nullptr)
{
return;
}
int splitYOffset;// = 20; // This offset is applied when doing the 2X scaling above to move the gui out of the way of the tool tips
int guiScale;// = ( minecraft->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN ? 3 : 2 );
int iPad=minecraft->player->GetXboxPad();
int iWidthOffset=0,iHeightOffset=0; // used to get the interface looking right on a 2 player split screen game
// 4J-PB - selected the gui scale based on the slider settings
if(minecraft->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN)
{
guiScale=app.GetGameSettings(iPad,eGameSetting_UISize) + 2;
}
else
{
guiScale=app.GetGameSettings(iPad,eGameSetting_UISizeSplitscreen) + 2;
}
ScreenSizeCalculator ssc(minecraft->options, minecraft->width, minecraft->height, guiScale );
int screenWidth = ssc.getWidth();
int screenHeight = ssc.getHeight();
int iSafezoneXHalf=0,iSafezoneYHalf=0,iSafezoneTopYHalf=0;
int iTooltipsYOffset=0;
int quickSelectWidth=182;
int quickSelectHeight=22;
float fScaleFactorWidth=1.0f,fScaleFactorHeight=1.0f;
bool bTwoPlayerSplitscreen=false;
currentGuiScaleFactor = static_cast<float>(guiScale); // Keep static copy of scale so we know how gui coordinates map to physical pixels - this is also affected by the viewport
switch(guiScale)
{
case 3:
splitYOffset = 0;
break;
case 4:
splitYOffset = -5;
break;
default: // 2
splitYOffset = 10;
break;
}
// Check which screen section this player is in
switch(minecraft->player->m_iScreenSection)
{
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
// single player
iSafezoneXHalf = screenWidth/20; // 5%
iSafezoneYHalf = screenHeight/20; // 5%
iSafezoneTopYHalf = iSafezoneYHalf;
iTooltipsYOffset=40+splitYOffset;
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
iSafezoneXHalf = screenWidth/10; // 5% (need to treat the whole screen is 2x this screen)
iSafezoneYHalf = splitYOffset;
iSafezoneTopYHalf = screenHeight/10;
fScaleFactorWidth=0.5f;
iWidthOffset=static_cast<int>((float)screenWidth * (1.0f - fScaleFactorWidth));
iTooltipsYOffset=44;
bTwoPlayerSplitscreen=true;
currentGuiScaleFactor *= 0.5f;
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
iSafezoneXHalf = screenWidth/10; // 5% (need to treat the whole screen is 2x this screen)
iSafezoneYHalf = splitYOffset + screenHeight/10;// 5% (need to treat the whole screen is 2x this screen)
iSafezoneTopYHalf = 0;
fScaleFactorWidth=0.5f;
iWidthOffset=static_cast<int>((float)screenWidth * (1.0f - fScaleFactorWidth));
iTooltipsYOffset=44;
bTwoPlayerSplitscreen=true;
currentGuiScaleFactor *= 0.5f;
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
iSafezoneXHalf = screenWidth/10; // 5% (the whole screen is 2x this screen)
iSafezoneYHalf = splitYOffset + screenHeight/10;// 5% (need to treat the whole screen is 2x this screen)
iSafezoneTopYHalf = screenHeight/10;
fScaleFactorHeight=0.5f;
iHeightOffset=screenHeight;
iTooltipsYOffset=44;
bTwoPlayerSplitscreen=true;
currentGuiScaleFactor *= 0.5f;
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
iSafezoneXHalf = 0;
iSafezoneYHalf = splitYOffset + screenHeight/10;// 5% (need to treat the whole screen is 2x this screen)
iSafezoneTopYHalf = splitYOffset + screenHeight/10;
fScaleFactorHeight=0.5f;
iHeightOffset=screenHeight;
iTooltipsYOffset=44;
bTwoPlayerSplitscreen=true;
currentGuiScaleFactor *= 0.5f;
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
iSafezoneXHalf = screenWidth/10; // 5% (the whole screen is 2x this screen)
iSafezoneYHalf = splitYOffset;
iSafezoneTopYHalf = screenHeight/10;
iTooltipsYOffset=44;
currentGuiScaleFactor *= 0.5f;
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
iSafezoneXHalf = 0;
iSafezoneYHalf = splitYOffset; // 5%
iSafezoneTopYHalf = screenHeight/10;
iTooltipsYOffset=44;
currentGuiScaleFactor *= 0.5f;
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
iSafezoneXHalf = screenWidth/10; // 5% (the whole screen is 2x this screen)
iSafezoneYHalf = splitYOffset + screenHeight/10; // 5% (the whole screen is 2x this screen)
iSafezoneTopYHalf = 0;
iTooltipsYOffset=44;
currentGuiScaleFactor *= 0.5f;
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
iSafezoneXHalf = 0;
iSafezoneYHalf = splitYOffset + screenHeight/10; // 5% (the whole screen is 2x this screen)
iSafezoneTopYHalf = 0;
iTooltipsYOffset=44;
currentGuiScaleFactor *= 0.5f;
break;
}
// 4J-PB - turn off the slot display if a xui menu is up, or if we're autosaving
bool bDisplayGui=!ui.GetMenuDisplayed(iPad) && !(app.GetXuiAction(iPad)==eAppAction_AutosaveSaveGameCapturedThumbnail);
// if tooltips are off, set the y offset to zero
if(app.GetGameSettings(iPad,eGameSetting_Tooltips)==0 && bDisplayGui)
{
switch(minecraft->player->m_iScreenSection)
{
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
iTooltipsYOffset=screenHeight/10;
break;
default:
//iTooltipsYOffset=screenHeight/10;
switch(guiScale)
{
case 3:
iTooltipsYOffset=28;//screenHeight/10;
break;
case 4:
iTooltipsYOffset=28;//screenHeight/10;
break;
default: // 2
iTooltipsYOffset=14;//screenHeight/10;
break;
}
break;
}
}
// 4J-PB - Turn off interface if eGameSetting_DisplayHUD is off - for screen shots/videos.
if ( app.GetGameSettings(iPad,eGameSetting_DisplayHUD)==0 )
{
bDisplayGui = false;
}
Font *font = minecraft->font;
minecraft->gameRenderer->setupGuiScreen(guiScale);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // 4J - added - this did actually get set in renderVignette but that code is currently commented out
if (Minecraft::useFancyGraphics())
{
renderVignette(minecraft->player->getBrightness(a), screenWidth, screenHeight);
}
/////////////////////////////////////////////////////////////////////////////////////
// Display the pumpkin screen effect
/////////////////////////////////////////////////////////////////////////////////////
shared_ptr<ItemInstance> headGear = minecraft->player->inventory->getArmor(3);
// 4J-PB - changing this to be per player
//if (!minecraft->options->thirdPersonView && headGear != NULL && headGear->id == Tile::pumpkin_Id) renderPumpkin(screenWidth, screenHeight);
if ((minecraft->player->ThirdPersonView()==0) && headGear != NULL && headGear->id == Tile::pumpkin_Id) renderPumpkin(screenWidth, screenHeight);
if (!minecraft->player->hasEffect(MobEffect::confusion))
{
float pt = minecraft->player->oPortalTime + (minecraft->player->portalTime - minecraft->player->oPortalTime) * a;
if (pt > 0)
{
renderTp(pt, screenWidth, screenHeight);
}
}
if (!minecraft->gameMode->isCutScene())
{
if(bDisplayGui && bTwoPlayerSplitscreen)
{
// need to apply scale factors depending on the mode
glPushMatrix();
glScalef(fScaleFactorWidth, fScaleFactorHeight, fScaleFactorWidth);
}
#if RENDER_HUD
/////////////////////////////////////////////////////////////////////////////////////
// Display the quick select background, the quick select selection, and the crosshair
/////////////////////////////////////////////////////////////////////////////////////
glColor4f(1, 1, 1, 1);
// 4J - this is where to set the blend factor for gui things
// use the primary player's settings
unsigned char ucAlpha=app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_InterfaceOpacity);
// If the user has started to navigate their quickselect bar, ignore the alpha setting, and display at default value
float fVal=fAlphaIncrementPerCent*(float)ucAlpha;
if(ucAlpha<80)
{
// check if we have the timer running for the opacity
unsigned int uiOpacityTimer=app.GetOpacityTimer(iPad);
if(uiOpacityTimer!=0)
{
if(uiOpacityTimer<10)
{
float fStep=(80.0f-(float)ucAlpha)/10.0f;
fVal=fAlphaIncrementPerCent*(80.0f-((10.0f-(float)uiOpacityTimer)*fStep));
}
else
{
fVal=fAlphaIncrementPerCent*80.0f;
}
}
else
{
fVal=fAlphaIncrementPerCent*(float)ucAlpha;
}
}
else
{
fVal=fAlphaIncrementPerCent*(float)ucAlpha;
}
RenderManager.StateSetBlendFactor(0xffffff |(((unsigned int)fVal)<<24));
currentGuiBlendFactor = fVal / 255.0f;
// RenderManager.StateSetBlendFactor(0x40ffffff);
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
blitOffset = -90;
/////////////////////////////////////////////////////////////////////////////////////
// Display the quick select background, the quick select selection, and the crosshair
/////////////////////////////////////////////////////////////////////////////////////
if(bDisplayGui)
{
MemSect(31);
minecraft->textures->bindTexture(TN_GUI_GUI); // 4J was L"/gui/gui.png"
MemSect(0);
shared_ptr<Inventory> inventory = minecraft->player->inventory;
if(bTwoPlayerSplitscreen)
{
// need to apply scale factors depending on the mode
// 4J Stu - Moved this push and scale further up as we still need to do it for the few HUD components not replaced by xui
//glPushMatrix();
//glScalef(fScaleFactorWidth, fScaleFactorHeight, fScaleFactorWidth);
// 4J-PB - move into the safe zone, and account for 2 player splitscreen
blit(iWidthOffset + (screenWidth - quickSelectWidth)/2, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset , 0, 0, 182, 22);
blit(iWidthOffset + (screenWidth - quickSelectWidth)/2 - 1 + inventory->selected * 20, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset - 1, 0, 22, 24, 22);
}
else
{
blit(iWidthOffset + screenWidth / 2 - quickSelectWidth / 2, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset , 0, 0, 182, 22);
blit(iWidthOffset + screenWidth / 2 - quickSelectWidth / 2 - 1 + inventory->selected * 20, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset - 1, 0, 22, 24, 22);
}
MemSect(31);
minecraft->textures->bindTexture(TN_GUI_ICONS);//L"/gui/icons.png"));
MemSect(0);
glEnable(GL_BLEND);
RenderManager.StateSetBlendFactor(0xffffff |(((unsigned int)fVal)<<24));
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
//glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
// 4J Stu - We don't want to adjust the cursor by the safezone, we want it centred
if(bTwoPlayerSplitscreen)
{
blit(iWidthOffset + screenWidth / 2 - 7, (iHeightOffset + screenHeight) / 2 - 7, 0, 0, 16, 16);
}
else
{
blit(screenWidth / 2 - 7, screenHeight / 2 - 7, 0, 0, 16, 16);
}
glDisable(GL_BLEND);
// if(bTwoPlayerSplitscreen)
// {
// glPopMatrix();
// }
}
bool blink = minecraft->player->invulnerableTime / 3 % 2 == 1;
if (minecraft->player->invulnerableTime < 10) blink = false;
int iHealth = minecraft->player->getHealth();
int iLastHealth = minecraft->player->lastHealth;
random->setSeed(tickCount * 312871);
bool foodBlink = false;
FoodData *foodData = minecraft->player->getFoodData();
int food = foodData->getFoodLevel();
int oldFood = foodData->getLastFoodLevel();
// if (false) //(true)
// {
// renderBossHealth();
// }
/////////////////////////////////////////////////////////////////////////////////////
// Display the experience, food, armour, health and the air bubbles
/////////////////////////////////////////////////////////////////////////////////////
if(bDisplayGui)
{
// 4J - added blend for fading gui
glEnable(GL_BLEND);
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
if (minecraft->gameMode->canHurtPlayer())
{
int xLeft, xRight;
// 4J Stu - TODO Work out proper positioning for splitscreen
if(bTwoPlayerSplitscreen)
{
xLeft = iWidthOffset + (screenWidth - quickSelectWidth)/2;
xRight = iWidthOffset + (screenWidth + quickSelectWidth)/2;
}
else
{
xLeft = (screenWidth - quickSelectWidth)/2;
xRight = (screenWidth + quickSelectWidth) / 2;
}
// render experience bar
int xpNeededForNextLevel = minecraft->player->getXpNeededForNextLevel();
if (xpNeededForNextLevel > 0)
{
int w = 182;
int progress = (int) (minecraft->player->experienceProgress * (float) (w + 1));
int yo = screenHeight - iSafezoneYHalf - iTooltipsYOffset - 8;
if(bTwoPlayerSplitscreen)
{
yo+=iHeightOffset;
}
blit(xLeft, yo, 0, 64, w, 5);
if (progress > 0)
{
blit(xLeft, yo, 0, 69, progress, 5);
}
}
int yLine1, yLine2;
if(bTwoPlayerSplitscreen)
{
//yo = iHeightOffset + screenHeight - 10 - iSafezoneYHalf - iTooltipsYOffset;
yLine1 = iHeightOffset + screenHeight - 18 - iSafezoneYHalf - iTooltipsYOffset;
yLine2 = yLine1 - 10;
}
else
{
//yo = screenHeight - 10 - iSafezoneYHalf - iTooltipsYOffset;
yLine1 = screenHeight - 18 - iSafezoneYHalf - iTooltipsYOffset;
yLine2 = yLine1 - 10;
}
double maxHealth = minecraft->localplayers[iPad]->getAttribute(SharedMonsterAttributes.MAX_HEALTH);
double totalAbsorption = minecraft->localplayers[iPad]->getAbsorptionAmount();
int numHealthRows = Mth.ceil((maxHealth + totalAbsorption) / 2 / (float) NUM_HEARTS_PER_ROW);
int healthRowHeight = Math.max(10 - (numHealthRows - 2), 3);
int yLine2 = yLine1 - (numHealthRows - 1) * healthRowHeight - 10;
absorption = totalAbsorption;
int armor = minecraft->player->getArmorValue();
int heartOffsetIndex = -1;
if (minecraft->player->hasEffect(MobEffect::regeneration))
{
heartOffsetIndex = tickCount % (int) ceil(maxHealth + 5);
}
// render health and armor
//minecraft.profiler.push("armor");
for (int i = 0; i < Player::MAX_HEALTH / 2; i++)
{
if (armor > 0)
{
int xo = xLeft + i * 8;
if (i * 2 + 1 < armor) blit(xo, yLine2, 16 + 2 * 9, 9, 9, 9);
if (i * 2 + 1 == armor) blit(xo, yLine2, 16 + 1 * 9, 9, 9, 9);
if (i * 2 + 1 > armor) blit(xo, yLine2, 16 + 0 * 9, 9, 9, 9);
}
}
//minecraft.profiler.popPush("health");
for (int i = Mth.ceil((maxHealth + totalAbsorption) / 2) - 1; i >= 0; i--)
{
int healthTexBaseX = 16;
if (minecraft.player.hasEffect(MobEffect.poison))
{
healthTexBaseX += 4 * 9;
}
else if (minecraft.player.hasEffect(MobEffect.wither))
{
healthTexBaseX += 8 * 9;
}
int bg = 0;
if (blink) bg = 1;
int rowIndex = Mth.ceil((i + 1) / (float) NUM_HEARTS_PER_ROW) - 1;
int xo = xLeft + (i % NUM_HEARTS_PER_ROW) * 8;
int yo = yLine1 - rowIndex * healthRowHeight;
if (currentHealth <= 4)
{
yo += random.nextInt(2);
}
if (i == heartOffsetIndex)
{
yo -= 2;
}
int y0 = 0;
// No hardcore on console
/*if (minecraft->level.getLevelData().isHardcore())
{
y0 = 5;
}*/
blit(xo, yo, 16 + bg * 9, 9 * y0, 9, 9);
if (blink)
{
if (i * 2 + 1 < oldHealth) blit(xo, yo, healthTexBaseX + 6 * 9, 9 * y0, 9, 9);
if (i * 2 + 1 == oldHealth) blit(xo, yo, healthTexBaseX + 7 * 9, 9 * y0, 9, 9);
}
if (absorption > 0)
{
if (absorption == totalAbsorption && totalAbsorption % 2 == 1)
{
blit(xo, yo, healthTexBaseX + 17 * 9, 9 * y0, 9, 9);
}
else
{
blit(xo, yo, healthTexBaseX + 16 * 9, 9 * y0, 9, 9);
}
absorption -= 2;
}
else
{
if (i * 2 + 1 < currentHealth) blit(xo, yo, healthTexBaseX + 4 * 9, 9 * y0, 9, 9);
if (i * 2 + 1 == currentHealth) blit(xo, yo, healthTexBaseX + 5 * 9, 9 * y0, 9, 9);
}
}
std::shared_ptr<Entity> riding = minecraft->localplayers[iPad].get()->riding;
std::shared_ptr<LivingEntity> living = dynamic_pointer_cast<LivingEntity>(riding);
if (riding == NULL)
{
// render food
for (int i = 0; i < FoodConstants::MAX_FOOD / 2; i++)
{
int yo = yLine1;
int texBaseX = 16;
int bg = 0;
if (minecraft->player->hasEffect(MobEffect::hunger))
{
texBaseX += 4 * 9;
bg = 13;
}
if (minecraft->player->getFoodData()->getSaturationLevel() <= 0)
{
if ((tickCount % (food * 3 + 1)) == 0)
{
yo += random->nextInt(3) - 1;
}
}
if (foodBlink) bg = 1;
int xo = xRight - i * 8 - 9;
blit(xo, yo, 16 + bg * 9, 9 * 3, 9, 9);
if (foodBlink)
{
if (i * 2 + 1 < oldFood) blit(xo, yo, texBaseX + 6 * 9, 9 * 3, 9, 9);
if (i * 2 + 1 == oldFood) blit(xo, yo, texBaseX + 7 * 9, 9 * 3, 9, 9);
}
if (i * 2 + 1 < food) blit(xo, yo, texBaseX + 4 * 9, 9 * 3, 9, 9);
if (i * 2 + 1 == food) blit(xo, yo, texBaseX + 5 * 9, 9 * 3, 9, 9);
}
}
else if (living != nullptr)
{
// Render mount health
int riderCurrentHealth = (int) ceil(living.get()->GetHealth());
float maxRiderHealth = living->GetMaxHealth();
int hearts = (int) (maxRiderHealth + .5f) / 2;
if (hearts > 30)
{
hearts = 30;
}
int yo = yLine1;
int baseHealth = 0;
while (hearts > 0)
{
int rowHearts = min(hearts, 10);
hearts -= rowHearts;
for (int i = 0; i < rowHearts; i++)
{
int texBaseX = 52;
int bg = 0;
if (foodBlink) bg = 1;
int xo = xRight - i * 8 - 9;
blit(xo, yo, texBaseX + bg * 9, 9 * 1, 9, 9);
if (i * 2 + 1 + baseHealth < riderCurrentHealth) blit(xo, yo, texBaseX + 4 * 9, 9 * 1, 9, 9);
if (i * 2 + 1 + baseHealth == riderCurrentHealth) blit(xo, yo, texBaseX + 5 * 9, 9 * 1, 9, 9);
}
yo -= 10;
baseHealth += 20;
}
}
// render air bubbles
if (minecraft->player->isUnderLiquid(Material::water))
{
int count = (int) ceil((minecraft->player->getAirSupply() - 2) * 10.0f / Player::TOTAL_AIR_SUPPLY);
int extra = (int) ceil((minecraft->player->getAirSupply()) * 10.0f / Player::TOTAL_AIR_SUPPLY) - count;
for (int i = 0; i < count + extra; i++)
{
// Air bubbles
if (i < count) blit(xRight - i * 8 - 9, yLine2, 16, 9 * 2, 9, 9);
else blit(xRight - i * 8 - 9, yLine2, 16 + 9, 9 * 2, 9, 9);
}
}
}
}
// 4J-PB - turn off the slot display if a xui menu is up
////////////////////////////
// render the slot contents
////////////////////////////
if(bDisplayGui)
{
// glDisable(GL_BLEND); 4J - removed - we want to be able to fade our gui
glEnable(GL_RESCALE_NORMAL);
Lighting::turnOnGui();
int x,y;
for (int i = 0; i < 9; i++)
{
if(bTwoPlayerSplitscreen)
{
x = iWidthOffset + screenWidth / 2 - 9 * 10 + i * 20 + 2;
y = iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22;
}
else
{
x = screenWidth / 2 - 9 * 10 + i * 20 + 2;
y = screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22;
}
this->renderSlot(i, x, y, a);
}
Lighting::turnOff();
glDisable(GL_RESCALE_NORMAL);
}
#endif // RENDER_HUD
// 4J - do render of crouched player. This code is largely taken from the inventory render of the player, with some special hard-coded positions
// worked out by hand from the xui implementation of the crouch icon
if(app.GetGameSettings(iPad,eGameSetting_AnimatedCharacter))
{
//int playerIdx = minecraft->player->GetXboxPad();
static int characterDisplayTimer[4] = {0};
if( !bDisplayGui )
{
characterDisplayTimer[iPad] = 0;
}
else if( minecraft->player->isSneaking() )
{
characterDisplayTimer[iPad] = 30;
}
else if( minecraft->player->isSprinting() )
{
characterDisplayTimer[iPad] = 30;
}
else if( minecraft->player->abilities.flying)
{
characterDisplayTimer[iPad] = 5; // quickly get rid of the player display if they stop flying
}
else if( characterDisplayTimer[iPad] > 0 )
{
--characterDisplayTimer[iPad];
}
bool displayCrouch = minecraft->player->isSneaking() || ( characterDisplayTimer[iPad] > 0 );
bool displaySprint = minecraft->player->isSprinting() || ( characterDisplayTimer[iPad] > 0 );
bool displayFlying = minecraft->player->abilities.flying || ( characterDisplayTimer[iPad] > 0 );
if( bDisplayGui && (displayCrouch || displaySprint || displayFlying) )
{
EntityRenderDispatcher::instance->prepare(minecraft->level, minecraft->textures, minecraft->font, minecraft->cameraTargetPlayer, minecraft->crosshairPickMob, minecraft->options, a);
glEnable(GL_RESCALE_NORMAL);
glEnable(GL_COLOR_MATERIAL);
// 4J - TomK now using safe zone values directly instead of the magic number calculation that lived here before (which only worked for medium scale, the other two were off!)
int xo = iSafezoneXHalf + 10;
int yo = iSafezoneTopYHalf + 10;
#ifdef __PSVITA__
// align directly with corners, there are no safe zones on vita
xo = 10;
yo = 10;
#endif
glPushMatrix();
glTranslatef(static_cast<float>(xo), static_cast<float>(yo), 50);
float ss = 12;
glScalef(-ss, ss, ss);
glRotatef(180, 0, 0, 1);
float oyr = minecraft->player->yRot;
float oyrO = minecraft->player->yRotO;
float oxr = minecraft->player->xRot;
int ofire = minecraft->player->onFire;
bool ofireflag = minecraft->player->getSharedFlag(Entity::FLAG_ONFIRE);
float xd = -40;
float yd = 10;
// 4J Stu - This is all based on the inventory player renderer, with changes to ensure that capes render correctly
// by minimising the changes to member variables of the player which are all related
glRotatef(45 + 90, 0, 1, 0);
Lighting::turnOn();
glRotatef(-45 - 90, 0, 1, 0);
glRotatef(-(float) atan(yd / 40.0f ) * 20, 1, 0, 0);
float bodyRot = (minecraft->player->yBodyRotO + (minecraft->player->yBodyRot - minecraft->player->yBodyRotO));
// Fixed rotation angle of degrees, adjusted by bodyRot to negate the rotation that occurs in the renderer
// bodyRot in the rotation below is a simplification of "180 - (180 - bodyRot)" where the first 180 is EntityRenderDispatcher::instance->playerRotY that we set below
// and (180 - bodyRot) is the angle of rotation that is performed within the mob renderer
glRotatef( bodyRot - ( (float) atan(xd / 40.0f) * 20), 0, 1, 0);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// Set head rotation to body rotation to make head static
minecraft->player->yRot = bodyRot;
minecraft->player->yRotO = minecraft->player->yRot;
minecraft->player->xRot = -(float) atan(yd / 40.0f) * 20;
minecraft->player->onFire = 0;
minecraft->player->setSharedFlag(Entity::FLAG_ONFIRE, false);
// 4J - TomK don't offset the player. it's easier to align it with the safe zones that way!
//glTranslatef(0, minecraft->player->heightOffset, 0);
glTranslatef(0, 0, 0);
EntityRenderDispatcher::instance->playerRotY = 180;
EntityRenderDispatcher::instance->isGuiRender = true;
EntityRenderDispatcher::instance->render(minecraft->player, 0, 0, 0, 0, 1);
EntityRenderDispatcher::instance->isGuiRender = false;
minecraft->player->yRot = oyr;
minecraft->player->yRotO = oyrO;
minecraft->player->xRot = oxr;
minecraft->player->onFire = ofire;
minecraft->player->setSharedFlag(Entity::FLAG_ONFIRE,ofireflag);
glPopMatrix();
Lighting::turnOff();
glDisable(GL_RESCALE_NORMAL);
}
}
}
#if RENDER_HUD
// Moved so the opacity blend is applied to it
if (bDisplayGui && minecraft->gameMode->hasExperience() && minecraft->player->experienceLevel > 0)
{
if (true)
{
bool blink = false;
int col = blink ? 0xffffff : 0x80ff20;
wchar_t formatted[10];
swprintf(formatted, 10, L"%d",minecraft->player->experienceLevel);
wstring str = formatted;
int x = iWidthOffset + (screenWidth - font->width(str)) / 2;
int y = screenHeight - iSafezoneYHalf - iTooltipsYOffset;
// If we're in creative mode, we don't need to offset the XP display so much
if (minecraft->gameMode->canHurtPlayer())
{
y-=18;
}
else
{
y-=13;
}
if(bTwoPlayerSplitscreen)
{
y+=iHeightOffset;
}
//int y = screenHeight - 31 - 4;
font->draw(str, x + 1, y, 0x000000);
font->draw(str, x - 1, y, 0x000000);
font->draw(str, x, y + 1, 0x000000);
font->draw(str, x, y - 1, 0x000000);
// font->draw(str, x + 1, y + 1, 0x000000);
// font->draw(str, x - 1, y + 1, 0x000000);
// font->draw(str, x + 1, y - 1, 0x000000);
// font->draw(str, x - 1, y - 1, 0x000000);
font->draw(str, x, y, col);
}
}
#endif // RENDER_HUD
// 4J - added to disable blends, which we have enabled previously to allow gui fading
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// if the player is falling asleep we render a dark overlay
if (minecraft->player->getSleepTimer() > 0)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_ALPHA_TEST);
int timer = minecraft->player->getSleepTimer();
float amount = static_cast<float>(timer) / static_cast<float>(Player::SLEEP_DURATION);
if (amount > 1)
{
// waking up
amount = 1.0f - (static_cast<float>(timer - Player::SLEEP_DURATION) / static_cast<float>(Player::WAKE_UP_DURATION));
}
int color = static_cast<int>(220.0f * amount) << 24 | (0x101020);
fill(0, 0, screenWidth/fScaleFactorWidth, screenHeight/fScaleFactorHeight, color);
glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
}
// 4J-PB - Request from Mojang to have a red death screen
if (!minecraft->player->isAlive())
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_ALPHA_TEST);
int timer = minecraft->player->getDeathFadeTimer();
float amount = static_cast<float>(timer) / static_cast<float>(Player::DEATHFADE_DURATION);
int color = static_cast<int>(220.0f * amount) << 24 | (0x200000);
fill(0, 0, screenWidth/fScaleFactorWidth, screenHeight/fScaleFactorHeight, color);
glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
}
// {
// String str = "" + minecraft.player.getFoodData().getExhaustionLevel() + ", " + minecraft.player.getFoodData().getSaturationLevel();
// int x = (screenWidth - font.width(str)) / 2;
// int y = screenHeight - 64;
// font.draw(str, x + 1, y, 0xffffff);
// }
#ifndef _FINAL_BUILD
MemSect(31);
// temporarily render overlay at all times so version is more obvious in bug reports
// we can turn this off once things stabilize
if (true)// minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
{
const int debugLeft = 1;
const int debugTop = 1;
const float maxContentWidth = 1200.f;
const float maxContentHeight = 420.f;
float scale = static_cast<float>(screenWidth - debugLeft - 8) / maxContentWidth;
float scaleV = static_cast<float>(screenHeight - debugTop - 80) / maxContentHeight;
if (scaleV < scale) scale = scaleV;
if (scale > 1.f) scale = 1.f;
if (scale < 0.5f) scale = 0.5f;
glPushMatrix();
glTranslatef(static_cast<float>(debugLeft), static_cast<float>(debugTop), 0.f);
glScalef(scale, scale, 1.f);
glTranslatef(static_cast<float>(-debugLeft), static_cast<float>(-debugTop), 0.f);
vector<wstring> lines;
// Only add version/branch lines if the watermark toggle is enabled
if (ClientConstants::SHOW_VERSION_WATERMARK) {
lines.push_back(ClientConstants::VERSION_STRING);
lines.push_back(ClientConstants::BRANCH_STRING);
}
if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
{
lines.push_back(minecraft->fpsString);
lines.push_back(L"E: " + std::to_wstring(minecraft->level->getAllEntities().size())); // Could maybe use entity::shouldRender to work out how many are rendered but thats like expensive
// TODO Add server information with packet counts - once multiplayer is more stable
int renderDistance = app.GetGameSettings(iPad, eGameSetting_RenderDistance);
// Calculate the chunk sections using 16 * (2n + 1)^2
lines.push_back(L"C: " + std::to_wstring(16 * (2 * renderDistance + 1) * (2 * renderDistance + 1)) + L" D: " + std::to_wstring(renderDistance));
lines.push_back(minecraft->gatherStats4()); // Chunk Cache
// Dimension
wstring dimension = L"unknown";
switch (minecraft->player->dimension)
{
case -1:
dimension = L"minecraft:the_nether";
break;
case 0:
dimension = L"minecraft:overworld";
break;
case 1:
dimension = L"minecraft:the_end";
break;
}
lines.push_back(dimension);
lines.push_back(L""); // Spacer
// Players block pos
int xBlockPos = Mth::floor(minecraft->player->x);
int yBlockPos = Mth::floor(minecraft->player->y);
int zBlockPos = Mth::floor(minecraft->player->z);
// Chunk player is in
int xChunkPos = xBlockPos >> 4;
int yChunkPos = yBlockPos >> 4;
int zChunkPos = zBlockPos >> 4;
// Players offset within the chunk
int xChunkOffset = xBlockPos & 15;
int yChunkOffset = yBlockPos & 15;
int zChunkOffset = zBlockPos & 15;
// Format the position like java with limited decumal places
WCHAR posString[44]; // Allows upto 7 digit positions (+-9_999_999)
swprintf(posString, 44, L"%.3f / %.5f / %.3f", minecraft->player->x, minecraft->player->y, minecraft->player->z);
lines.push_back(L"XYZ: " + std::wstring(posString));
lines.push_back(L"Block: " + std::to_wstring(static_cast<int>(xBlockPos)) + L" " + std::to_wstring(static_cast<int>(yBlockPos)) + L" " + std::to_wstring(static_cast<int>(zBlockPos)));
lines.push_back(L"Chunk: " + std::to_wstring(xChunkOffset) + L" " + std::to_wstring(yChunkOffset) + L" " + std::to_wstring(zChunkOffset) + L" in " + std::to_wstring(xChunkPos) + L" " + std::to_wstring(yChunkPos) + L" " + std::to_wstring(zChunkPos));
// Wrap the yRot to 360 then adjust to (-180 to 180) range to match java
float yRotDisplay = fmod(minecraft->player->yRot, 360.0f);
if (yRotDisplay > 180.0f)
{
yRotDisplay -= 360.0f;
}
if (yRotDisplay < -180.0f)
{
yRotDisplay += 360.0f;
}
// Generate the angle string in the format "yRot / xRot" with one decimal place, similar to java edition
WCHAR angleString[16];
swprintf(angleString, 16, L"%.1f / %.1f", yRotDisplay, minecraft->player->xRot);
// Work out the named direction
int direction = Mth::floor(minecraft->player->yRot * 4.0f / 360.0f + 0.5) & 0x3;
wstring cardinalDirection;
switch (direction)
{
case 0:
cardinalDirection = L"south";
break;
case 1:
cardinalDirection = L"west";
break;
case 2:
cardinalDirection = L"north";
break;
case 3:
cardinalDirection = L"east";
break;
}
lines.push_back(L"Facing: " + cardinalDirection + L" (" + angleString + L")");
// We have to limit y to 256 as we don't get any information past that
if (minecraft->level != NULL && minecraft->level->hasChunkAt(xBlockPos, fmod(yBlockPos, 256), zBlockPos))
{
LevelChunk *chunkAt = minecraft->level->getChunkAt(xBlockPos, zBlockPos);
if (chunkAt != NULL)
{
int skyLight = chunkAt->getBrightness(LightLayer::Sky, xChunkOffset, yChunkOffset, zChunkOffset);
int blockLight = chunkAt->getBrightness(LightLayer::Block, xChunkOffset, yChunkOffset, zChunkOffset);
int maxLight = fmax(skyLight, blockLight);
lines.push_back(L"Light: " + std::to_wstring(maxLight) + L" (" + std::to_wstring(skyLight) + L" sky, " + std::to_wstring(blockLight) + L" block)");
lines.push_back(L"CH S: " + std::to_wstring(chunkAt->getHeightmap(xChunkOffset, zChunkOffset)));
Biome *biome = chunkAt->getBiome(xChunkOffset, zChunkOffset, minecraft->level->getBiomeSource());
lines.push_back(L"Biome: " + biome->m_name + L" (" + std::to_wstring(biome->id) + L")");
lines.push_back(L"Difficulty: " + std::to_wstring(minecraft->level->difficulty) + L" (Day " + std::to_wstring(minecraft->level->getGameTime() / Level::TICKS_PER_DAY) + L")");
}
}
// This is all LCE only stuff, it was never on java
lines.push_back(L""); // Spacer
lines.push_back(L"Seed: " + std::to_wstring(minecraft->level->getLevelData()->getSeed()));
lines.push_back(minecraft->gatherStats1()); // Time to autosave
lines.push_back(minecraft->gatherStats2()); // Empty currently - CPlatformNetworkManagerStub::GatherStats()
lines.push_back(minecraft->gatherStats3()); // RTT
}
#ifdef _DEBUG // Only show terrain features in debug builds not release
// TERRAIN FEATURES
if (minecraft->level->dimension->id == 0)
{
wstring wfeature[eTerrainFeature_Count];
wfeature[eTerrainFeature_Stronghold] = L"Stronghold: ";
wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: ";
wfeature[eTerrainFeature_Village] = L"Village: ";
wfeature[eTerrainFeature_Ravine] = L"Ravine: ";
float maxW = static_cast<float>(screenWidth - debugLeft - 8) / scale;
float maxWForContent = maxW - static_cast<float>(font->width(L"..."));
bool truncated[eTerrainFeature_Count] = {};
for (size_t i = 0; i < app.m_vTerrainFeatures.size(); i++)
{
FEATURE_DATA *pFeatureData = app.m_vTerrainFeatures[i];
int type = pFeatureData->eTerrainFeature;
if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine)
{
continue;
}
if (truncated[type])
{
continue;
}
wstring itemInfo = L"[" + std::to_wstring(pFeatureData->x * 16) + L", " + std::to_wstring(pFeatureData->z * 16) + L"] ";
if (font->width(wfeature[type] + itemInfo) <= maxWForContent)
{
wfeature[type] += itemInfo;
}
else
{
wfeature[type] += L"...";
truncated[type] = true;
}
}
lines.push_back(L""); // Add a spacer line
for (int i = eTerrainFeature_Stronghold; i <= static_cast<int>(eTerrainFeature_Ravine); i++)
{
lines.push_back(wfeature[i]);
}
lines.push_back(L"");
}
#endif
// Loop through the lines and draw them all on screen
int yPos = debugTop;
for (const auto &line : lines)
{
drawString(font, line, debugLeft, yPos, 0xffffff);
yPos += 10;
}
glPopMatrix();
}
MemSect(0);
#endif
lastTickA = a;
// 4J Stu - This is now displayed in a xui scene
#if 0
// Jukebox CD message
if (overlayMessageTime > 0)
{
float t = overlayMessageTime - a;
int alpha = (int) (t * 256 / 20);
if (alpha > 255) alpha = 255;
if (alpha > 0)
{
glPushMatrix();
if(bTwoPlayerSplitscreen)
{
glTranslatef((float)((screenWidth / 2)+iWidthOffset), ((float)(screenHeight+iHeightOffset)) - iTooltipsYOffset -12 -iSafezoneYHalf, 0);
}
else
{
glTranslatef(((float)screenWidth) / 2, ((float)screenHeight) - iTooltipsYOffset - 12 -iSafezoneYHalf, 0);
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int col = 0xffffff;
if (animateOverlayMessageColor)
{
col = Color::HSBtoRGB(t / 50.0f, 0.7f, 0.6f) & 0xffffff;
}
// 4J-PB - this is the string displayed when cds are placed in a jukebox
font->draw(overlayMessageString,-font->width(overlayMessageString) / 2, -20, col + (alpha << 24));
glDisable(GL_BLEND);
glPopMatrix();
}
}
#endif
unsigned int max = 10;
bool isChatting = false;
if (dynamic_cast<ChatScreen *>(minecraft->screen) != NULL)
{
max = 20;
isChatting = true;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_ALPHA_TEST);
#if 0 // defined(_WINDOWS64) // Temporarily disable this chat in favor of iggy chat until we have better visual parity
glPushMatrix();
glTranslatef(0.0f, static_cast<float>(screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22) - 24.0f, 0.0f);
if(bDisplayGui)
{
int iPad=minecraft->player->GetXboxPad();
for (unsigned int i = 0; i < guiMessages[iPad].size() && i < max; i++)
{
if (guiMessages[iPad][i].ticks < 20 * 10 || isChatting)
{
double t = guiMessages[iPad][i].ticks / (20 * 10.0);
t = 1 - t;
t = t * 10;
if (t < 0) t = 0;
if (t > 1) t = 1;
t = t * t;
int alpha = static_cast<int>(255 * t);
if (isChatting) alpha = 255;
if (alpha > 0)
{
int x = iSafezoneXHalf+2;
int y = -(static_cast<int>(i)) * 9;
if(bTwoPlayerSplitscreen)
{
y+= iHeightOffset;
}
wstring msg = guiMessages[iPad][i].string;
this->fill(0, y - 1, screenWidth/fScaleFactorWidth, y + 8, (alpha / 2) << 24);
glEnable(GL_BLEND);
font->drawShadow(msg, iSafezoneXHalf+4, y, 0xffffff + (alpha << 24));
}
}
}
}
glPopMatrix();
#endif
// 4J Stu - Copied over but not used
#if 0
if (minecraft.player instanceof MultiplayerLocalPlayer && minecraft.options.keyPlayerList.isDown)
{
ClientConnection connection = ((MultiplayerLocalPlayer) minecraft.player).connection;
List<PlayerInfo> playerInfos = connection.playerInfos;
int slots = connection.maxPlayers;
int rows = slots;
int cols = 1;
while (rows > 20) {
cols++;
rows = (slots + cols - 1) / cols;
}
/*
* int fakeCount = 39; while (playerInfos.size() > fakeCount)
* playerInfos.remove(playerInfos.size() - 1); while (playerInfos.size() <
* fakeCount) playerInfos.add(new PlayerInfo("fiddle"));
*/
int slotWidth = 300 / cols;
if (slotWidth > 150) slotWidth = 150;
int xxo = (screenWidth - cols * slotWidth) / 2;
int yyo = 10;
fill(xxo - 1, yyo - 1, xxo + slotWidth * cols, yyo + 9 * rows, 0x80000000);
for (int i = 0; i < slots; i++) {
int xo = xxo + i % cols * slotWidth;
int yo = yyo + i / cols * 9;
fill(xo, yo, xo + slotWidth - 1, yo + 8, 0x20ffffff);
glColor4f(1, 1, 1, 1);
glEnable(GL_ALPHA_TEST);
if (i < playerInfos.size()) {
PlayerInfo pl = playerInfos.get(i);
font.drawShadow(pl.name, xo, yo, 0xffffff);
minecraft.textures.bind(minecraft.textures.loadTexture("/gui/icons.png"));
int xt = 0;
int yt = 0;
xt = 0;
yt = 0;
if (pl.latency < 0) yt = 5;
else if (pl.latency < 150) yt = 0;
else if (pl.latency < 300) yt = 1;
else if (pl.latency < 600) yt = 2;
else if (pl.latency < 1000) yt = 3;
else yt = 4;
blitOffset += 100;
blit(xo + slotWidth - 12, yo, 0 + xt * 10, 176 + yt * 8, 10, 8);
blitOffset -= 100;
}
}
}
#endif
if(bDisplayGui && bTwoPlayerSplitscreen)
{
// pop the scaled matrix
glPopMatrix();
}
glColor4f(1, 1, 1, 1);
glDisable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
}
// Moved to the xui base scene
// void Gui::renderBossHealth(void)
// {
// if (EnderDragonRenderer::bossInstance == NULL) return;
//
// shared_ptr<EnderDragon> boss = EnderDragonRenderer::bossInstance;
// EnderDragonRenderer::bossInstance = NULL;
//
// Minecraft *pMinecraft=Minecraft::GetInstance();
//
// Font *font = pMinecraft->font;
//
// ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys);
// int screenWidth = ssc.getWidth();
//
// int w = 182;
// int xLeft = screenWidth / 2 - w / 2;
//
// int progress = (int) (boss->getSynchedHealth() / (float) boss->getMaxHealth() * (float) (w + 1));
//
// int yo = 12;
// blit(xLeft, yo, 0, 74, w, 5);
// blit(xLeft, yo, 0, 74, w, 5);
// if (progress > 0)
// {
// blit(xLeft, yo, 0, 79, progress, 5);
// }
//
// wstring msg = L"Boss health - NON LOCALISED";
// font->drawShadow(msg, screenWidth / 2 - font->width(msg) / 2, yo - 10, 0xff00ff);
// glColor4f(1, 1, 1, 1);
// glBindTexture(GL_TEXTURE_2D, pMinecraft->textures->loadTexture(TN_GUI_ICONS) );//"/gui/icons.png"));
//
// }
void Gui::renderPumpkin(int w, int h)
{
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1, 1, 1, 1);
glDisable(GL_ALPHA_TEST);
MemSect(31);
minecraft->textures->bindTexture(&PUMPKIN_BLUR_LOCATION);
MemSect(0);
Tesselator *t = Tesselator::getInstance();
t->begin();
t->vertexUV(static_cast<float>(0), static_cast<float>(h), static_cast<float>(-90), static_cast<float>(0), static_cast<float>(1));
t->vertexUV(static_cast<float>(w), static_cast<float>(h), static_cast<float>(-90), static_cast<float>(1), static_cast<float>(1));
t->vertexUV(static_cast<float>(w), static_cast<float>(0), static_cast<float>(-90), static_cast<float>(1), static_cast<float>(0));
t->vertexUV(static_cast<float>(0), static_cast<float>(0), static_cast<float>(-90), static_cast<float>(0), static_cast<float>(0));
t->end();
glDepthMask(true);
glEnable(GL_DEPTH_TEST);
glEnable(GL_ALPHA_TEST);
glColor4f(1, 1, 1, 1);
}
void Gui::renderVignette(float br, int w, int h)
{
br = 1 - br;
if (br < 0) br = 0;
if (br > 1) br = 1;
tbr += (br - tbr) * 0.01f;
#if 0 // 4J - removed - TODO put back when we have blend functions implemented
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
glColor4f(tbr, tbr, tbr, 1);
glBindTexture(GL_TEXTURE_2D, minecraft->textures->loadTexture(TN__BLUR__MISC_VIGNETTE));//L"%blur%/misc/vignette.png"));
Tesselator *t = Tesselator::getInstance();
t->begin();
t->vertexUV((float)(0), (float)( h), (float)( -90), (float)( 0), (float)( 1));
t->vertexUV((float)(w), (float)( h), (float)( -90), (float)( 1), (float)( 1));
t->vertexUV((float)(w), (float)( 0), (float)( -90), (float)( 1), (float)( 0));
t->vertexUV((float)(0), (float)( 0), (float)( -90), (float)( 0), (float)( 0));
t->end();
glDepthMask(true);
glEnable(GL_DEPTH_TEST);
glColor4f(1, 1, 1, 1);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif
}
void Gui::renderTp(float br, int w, int h)
{
if (br < 1)
{
br = br * br;
br = br * br;
br = br * 0.8f + 0.2f;
}
glDisable(GL_ALPHA_TEST);
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1, 1, 1, br);
MemSect(31);
minecraft->textures->bindTexture(&TextureAtlas::LOCATION_BLOCKS);
MemSect(0);
Icon *slot = Tile::portalTile->getTexture(Facing::UP);
float u0 = slot->getU0();
float v0 = slot->getV0();
float u1 = slot->getU1();
float v1 = slot->getV1();
Tesselator *t = Tesselator::getInstance();
t->begin();
t->vertexUV(static_cast<float>(0), static_cast<float>(h), static_cast<float>(-90), (float)( u0), (float)( v1));
t->vertexUV(static_cast<float>(w), static_cast<float>(h), static_cast<float>(-90), (float)( u1), (float)( v1));
t->vertexUV(static_cast<float>(w), static_cast<float>(0), static_cast<float>(-90), (float)( u1), (float)( v0));
t->vertexUV(static_cast<float>(0), static_cast<float>(0), static_cast<float>(-90), (float)( u0), (float)( v0));
t->end();
glDepthMask(true);
glEnable(GL_DEPTH_TEST);
glEnable(GL_ALPHA_TEST);
glColor4f(1, 1, 1, 1);
}
void Gui::renderSlot(int slot, int x, int y, float a)
{
shared_ptr<ItemInstance> item = minecraft->player->inventory->items[slot];
if (item == NULL) return;
float pop = item->popTime - a;
if (pop > 0)
{
glPushMatrix();
float squeeze = 1 + pop / static_cast<float>(Inventory::POP_TIME_DURATION);
glTranslatef(static_cast<float>(x + 8), static_cast<float>(y + 12), 0);
glScalef(1 / squeeze, (squeeze + 1) / 2, 1);
glTranslatef(static_cast<float>(-(x + 8)), static_cast<float>(-(y + 12)), 0);
}
itemRenderer->renderAndDecorateItem(minecraft->font, minecraft->textures, item, x, y);
if (pop > 0)
{
glPopMatrix();
}
itemRenderer->renderGuiItemDecorations(minecraft->font, minecraft->textures, item, x, y);
}
void Gui::tick()
{
if (overlayMessageTime > 0) overlayMessageTime--;
tickCount++;
for(int iPad=0;iPad<XUSER_MAX_COUNT;iPad++)
{
// 4J Stu - Fix for #10929 - MP LAB: Network Disconnects: Host does not receive an error message stating the client left the game when viewing the Pause Menu.
// We don't show the guiMessages when a menu is up, so don't fade them out
if(!ui.GetMenuDisplayed(iPad))
{
for (auto& it : guiMessages[iPad])
{
it.ticks++;
}
}
}
}
void Gui::clearMessages(int iPad)
{
if(iPad==-1)
{
for(int i=0;i<XUSER_MAX_COUNT;i++)
{
if(minecraft->localplayers[i])
{
guiMessages[i].clear();
}
}
}
else
{
guiMessages[iPad].clear();
}
}
void Gui::addMessage(const wstring& _string,int iPad,bool bIsDeathMessage)
{
wstring string = _string; // 4J - Take copy of input as it is const
//int iScale=1;
//if((minecraft->player->m_iScreenSection==C4JRender::VIEWPORT_TYPE_SPLIT_TOP) ||
// (minecraft->player->m_iScreenSection==C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM))
//{
// iScale=2;
//}
// while (minecraft->font->width(string) > (m_iMaxMessageWidth*iScale))
//{
// unsigned int i = 1;
// while (i < string.length() && minecraft->font->width(string.substr(0, i + 1)) <= (m_iMaxMessageWidth*iScale))
// {
// i++;
// }
// int iLast=string.find_last_of(L" ",i);
// // if a space was found, include the space on this line
// if(iLast!=i)
// {
// iLast++;
// }
// addMessage(string.substr(0, iLast), iPad);
// string = string.substr(iLast);
// }
int maximumChars;
switch(minecraft->player->m_iScreenSection)
{
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
if(RenderManager.IsHiDef())
{
maximumChars = 105;
}
else
{
maximumChars = 55;
}
#ifdef __PSVITA__
maximumChars = 90;
#endif
switch(XGetLanguage())
{
case XC_LANGUAGE_JAPANESE:
case XC_LANGUAGE_TCHINESE:
case XC_LANGUAGE_KOREAN:
if(RenderManager.IsHiDef())
{
maximumChars = 70;
}
else
{
maximumChars = 35;
}
#ifdef __PSVITA__
maximumChars = 55;
#endif
break;
}
break;
default:
maximumChars = 55;
switch(XGetLanguage())
{
case XC_LANGUAGE_JAPANESE:
case XC_LANGUAGE_TCHINESE:
case XC_LANGUAGE_KOREAN:
maximumChars = 35;
break;
}
break;
}
while (string.length() > maximumChars)
{
unsigned int i = 1;
while (i < string.length() && (i + 1) <= maximumChars)
{
i++;
}
size_t iLast=string.find_last_of(L" ",i);
switch(XGetLanguage())
{
case XC_LANGUAGE_JAPANESE:
case XC_LANGUAGE_TCHINESE:
case XC_LANGUAGE_KOREAN:
iLast = maximumChars;
break;
default:
iLast=string.find_last_of(L" ",i);
break;
}
// if a space was found, include the space on this line
if(iLast!=i)
{
iLast++;
}
addMessage(string.substr(0, iLast), iPad, bIsDeathMessage);
string = string.substr(iLast);
}
if(iPad==-1)
{
// add to all
for(int i=0;i<XUSER_MAX_COUNT;i++)
{
if(minecraft->localplayers[i] && !(bIsDeathMessage && app.GetGameSettings(i,eGameSetting_DeathMessages)==0))
{
guiMessages[i].insert(guiMessages[i].begin(), GuiMessage(string));
while (guiMessages[i].size() > 50)
{
guiMessages[i].pop_back();
}
}
}
}
else if(!(bIsDeathMessage && app.GetGameSettings(iPad,eGameSetting_DeathMessages)==0))
{
guiMessages[iPad].insert(guiMessages[iPad].begin(), GuiMessage(string));
while (guiMessages[iPad].size() > 50)
{
guiMessages[iPad].pop_back();
}
}
}
// 4J Added
float Gui::getOpacity(int iPad, DWORD index)
{
float opacityPercentage = 0;
if (guiMessages[iPad].size() > index && guiMessages[iPad][index].ticks < 20 * 10)
{
double t = guiMessages[iPad][index].ticks / (20 * 10.0);
t = 1 - t;
t = t * 10;
if (t < 0) t = 0;
if (t > 1) t = 1;
t = t * t;
opacityPercentage = t;
}
return opacityPercentage;
}
float Gui::getJukeboxOpacity(int iPad)
{
float t = overlayMessageTime - lastTickA;
int alpha = static_cast<int>(t * 256 / 20);
if (alpha > 255) alpha = 255;
alpha /= 255;
return alpha;
}
void Gui::setNowPlaying(const wstring& string)
{
// overlayMessageString = L"Now playing: " + string;
overlayMessageString = app.GetString(IDS_NOWPLAYING) + string;
overlayMessageTime = 20 * 3;
animateOverlayMessageColor = true;
}
void Gui::displayClientMessage(int messageId, int iPad)
{
//Language *language = Language::getInstance();
wstring languageString = app.GetString(messageId);//language->getElement(messageId);
addMessage(languageString, iPad);
}
// 4J Added
void Gui::renderGraph(int dataLength, int dataPos, int64_t *dataA, float dataAScale, int dataAWarning, int64_t *dataB, float dataBScale, int dataBWarning)
{
int height = minecraft->height;
// This causes us to cover xScale*dataLength pixels in the horizontal
int xScale = 1;
if(dataA != NULL && dataB != NULL) xScale = 2;
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, static_cast<float>(minecraft->width), static_cast<float>(height), 0, 1000, 3000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -2000);
glLineWidth(1);
glDisable(GL_TEXTURE_2D);
Tesselator *t = Tesselator::getInstance();
t->begin(GL_LINES);
for (int i = 0; i < dataLength; i++)
{
int col = ((i - dataPos) & (dataLength - 1)) * 255 / dataLength;
int cc = col * col / 255;
cc = cc * cc / 255;
int cc2 = cc * cc / 255;
cc2 = cc2 * cc2 / 255;
if( dataA != NULL )
{
if (dataA[i] > dataAWarning)
{
t->color(0xff000000 + cc * 65536);
}
else
{
t->color(0xff000000 + cc * 256);
}
int64_t aVal = dataA[i] / dataAScale;
t->vertex((float)(xScale*i + 0.5f), (float)( height - aVal + 0.5f), static_cast<float>(0));
t->vertex((float)(xScale*i + 0.5f), (float)( height + 0.5f), static_cast<float>(0));
}
if( dataB != NULL )
{
if (dataB[i]>dataBWarning)
{
t->color(0xff000000 + cc * 65536 + cc * 256 + cc * 1);
}
else
{
t->color(0xff808080 + cc/2 * 256);
}
int64_t bVal = dataB[i] / dataBScale;
t->vertex((float)(xScale*i + (xScale - 1) + 0.5f), (float)( height - bVal + 0.5f), static_cast<float>(0));
t->vertex((float)(xScale*i + (xScale - 1) + 0.5f), (float)( height + 0.5f), static_cast<float>(0));
}
}
t->end();
glEnable(GL_TEXTURE_2D);
}
void Gui::renderStackedGraph(int dataPos, int dataLength, int dataSources, int64_t (*func)(unsigned int dataPos, unsigned int dataSource) )
{
int height = minecraft->height;
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, static_cast<float>(minecraft->width), static_cast<float>(height), 0, 1000, 3000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -2000);
glLineWidth(1);
glDisable(GL_TEXTURE_2D);
Tesselator *t = Tesselator::getInstance();
t->begin(GL_LINES);
int64_t thisVal = 0;
int64_t topVal = 0;
for (int i = 0; i < dataLength; i++)
{
thisVal = 0;
topVal = 0;
int col = ((i - dataPos) & (dataLength - 1)) * 255 / dataLength;
int cc = col * col / 255;
cc = cc * cc / 255;
int cc2 = cc * cc / 255;
cc2 = cc2 * cc2 / 255;
for(unsigned int source = 0; source < dataSources; ++source )
{
thisVal = func( i, source );
if( thisVal > 0 )
{
float vary = static_cast<float>(source)/dataSources;
int fColour = floor(vary * 0xffffff);
int colour = 0xff000000 + fColour;
//printf("Colour is %x\n", colour);
t->color(colour);
t->vertex((float)(i + 0.5f), (float)( height - topVal - thisVal + 0.5f), static_cast<float>(0));
t->vertex((float)(i + 0.5f), (float)( height - topVal + 0.5f), static_cast<float>(0));
topVal += thisVal;
}
}
// Draw some horizontals
for(unsigned int horiz = 1; horiz < 7; ++horiz )
{
t->color(0xff000000);
t->vertex((float)(0 + 0.5f), (float)( height - (horiz*100) + 0.5f), static_cast<float>(0));
t->vertex((float)(dataLength + 0.5f), (float)( height - (horiz*100) + 0.5f), static_cast<float>(0));
}
}
t->end();
glEnable(GL_TEXTURE_2D);
}