forked from Kolyah35/minecraft-pe-0.6.1
(MAJOR)Added Java Beta/Normal Shading, toggleble in settings Fixed and restored the unused Item Switching Animation, toggleble in tweaks too Added Dynamic Texture for Lava Added option to use Block Outline Selection which was unused normally Added Split Touch Controls into Options Mobs will now drop cooked variants of their meat if they died by fire Fixed Untranslated Strings in Settings (MAJOR) Ravines and Lava/Water pools have been fixed and renabled Tweaked BasicTree to hopefully speed up generation a bit, might disable them temporarily if they keep being slow You can now grow Fancy Oak Trees using saplings.
1164 lines
34 KiB
C++
Executable File
1164 lines
34 KiB
C++
Executable File
#include "Gui.h"
|
|
#include "Font.h"
|
|
#include "client/Options.h"
|
|
#include "platform/input/Keyboard.h"
|
|
#include "screens/IngameBlockSelectionScreen.h"
|
|
#include "screens/ChatScreen.h"
|
|
#include "screens/ConsoleScreen.h"
|
|
#include "../Minecraft.h"
|
|
#include "../player/LocalPlayer.h"
|
|
#include "../renderer/Tesselator.h"
|
|
#include "../renderer/TileRenderer.h"
|
|
#include "../renderer/LevelRenderer.h"
|
|
#include "../renderer/GameRenderer.h"
|
|
#include "../renderer/entity/ItemRenderer.h"
|
|
#include "../player/input/IInputHolder.h"
|
|
#include "../gamemode/GameMode.h"
|
|
#include "../gamemode/CreativeMode.h"
|
|
#include "../renderer/Textures.h"
|
|
#include "../../AppConstants.h"
|
|
#include "../../world/entity/player/Inventory.h"
|
|
#include "../../world/level/material/Material.h"
|
|
#include "../../world/item/Item.h"
|
|
#include "../../world/item/ItemInstance.h"
|
|
#include "../../platform/input/Mouse.h"
|
|
#include "../../world/level/Level.h"
|
|
#include "../../world/PosTranslator.h"
|
|
#include "../../platform/time.h"
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
|
|
float Gui::InvGuiScale = 1.0f / 3.0f;
|
|
float Gui::GuiScale = 1.0f / Gui::InvGuiScale;
|
|
const float Gui::DropTicks = 40.0f;
|
|
|
|
//#include <android/log.h>
|
|
|
|
Gui::Gui(Minecraft* minecraft)
|
|
: minecraft(minecraft),
|
|
tickCount(0),
|
|
progress(0),
|
|
overlayMessageTime(0),
|
|
animateOverlayMessageColor(false),
|
|
chatScrollOffset(0),
|
|
tbr(1),
|
|
_inventoryNeedsUpdate(true),
|
|
_flashSlotId(-1),
|
|
_flashSlotStartTime(-1),
|
|
_slotFont(NULL),
|
|
_numSlots(4),
|
|
_currentDropTicks(-1),
|
|
_currentDropSlot(-1),
|
|
MAX_MESSAGE_WIDTH(240),
|
|
itemNameOverlayTime(2),
|
|
_openInventorySlot(minecraft->useTouchscreen())
|
|
{
|
|
glGenBuffers2(1, &_inventoryRc.vboId);
|
|
glGenBuffers2(1, &rcFeedbackInner.vboId);
|
|
glGenBuffers2(1, &rcFeedbackOuter.vboId);
|
|
//Gui::InvGuiScale = 1.0f / (int) (3 * Minecraft::width / 854);
|
|
}
|
|
|
|
Gui::~Gui()
|
|
{
|
|
if (_slotFont)
|
|
delete _slotFont;
|
|
|
|
glDeleteBuffers(1, &_inventoryRc.vboId);
|
|
}
|
|
|
|
void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) {
|
|
|
|
if (!minecraft->level || !minecraft->player)
|
|
return;
|
|
|
|
//minecraft->gameRenderer->setupGuiScreen();
|
|
Font* font = minecraft->font;
|
|
|
|
const bool isTouchInterface = minecraft->useTouchscreen();
|
|
|
|
const int screenWidth = (int)(minecraft->width * InvGuiScale);
|
|
const int screenHeight = (int)(minecraft->height * InvGuiScale);
|
|
blitOffset = -90;
|
|
renderProgressIndicator(isTouchInterface, screenWidth, screenHeight, a);
|
|
|
|
glColor4f2(1, 1, 1, 1);
|
|
|
|
// H: 4
|
|
// T: 7
|
|
// L: 6
|
|
// F: 3
|
|
int ySlot = screenHeight - 16 - 3;
|
|
|
|
if (!minecraft->options.getBooleanValue(OPTIONS_HIDEGUI)) {
|
|
if (minecraft->gameMode->canHurtPlayer()) {
|
|
minecraft->textures->loadAndBindTexture("gui/icons.png");
|
|
Tesselator& t = Tesselator::instance;
|
|
t.beginOverride();
|
|
t.colorABGR(0xffffffff);
|
|
renderHearts();
|
|
renderBubbles();
|
|
t.endOverrideAndDraw();
|
|
}
|
|
}
|
|
|
|
// @todo - Shredder: I added this here but currently viginette is broken so i cant do much about it.
|
|
// if (minecraft->options.getBooleanValue(OPTIONS_FANCY_GRAPHICS)){
|
|
// this->renderVignette(this->minecraft->player->getBrightness(a), screenWidth, screenHeight);
|
|
// }
|
|
// shredder end
|
|
|
|
if(minecraft->player->getSleepTimer() > 0) {
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
renderSleepAnimation(screenWidth, screenHeight);
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
if (!minecraft->options.getBooleanValue(OPTIONS_HIDEGUI)) {
|
|
renderToolBar(a, ySlot, screenWidth);
|
|
|
|
glEnable(GL_BLEND);
|
|
bool isChatting = (minecraft->screen && (dynamic_cast<ChatScreen*>(minecraft->screen) || dynamic_cast<ConsoleScreen*>(minecraft->screen)));
|
|
unsigned int max = 10;
|
|
if (isChatting) {
|
|
int lineHeight = 9;
|
|
max = (screenHeight - 48) / lineHeight;
|
|
if (max < 1) max = 1;
|
|
int maxScroll = (int)guiMessages.size() - (int)max;
|
|
if (maxScroll < 0) maxScroll = 0;
|
|
if (chatScrollOffset > maxScroll) chatScrollOffset = maxScroll;
|
|
} else {
|
|
chatScrollOffset = 0;
|
|
}
|
|
renderChatMessages(screenHeight, max, isChatting, font);
|
|
#if !defined(RPI)
|
|
renderOnSelectItemNameText(screenWidth, font, ySlot);
|
|
#endif
|
|
#if defined(RPI)
|
|
renderDebugInfo();
|
|
#endif
|
|
|
|
if (Keyboard::isKeyDown(Keyboard::KEY_TAB)) {
|
|
renderPlayerList(font, screenWidth, screenHeight);
|
|
}
|
|
|
|
if (minecraft->options.getBooleanValue(OPTIONS_RENDER_DEBUG))
|
|
renderDebugInfo();
|
|
}
|
|
|
|
glDisable(GL_BLEND);
|
|
glEnable2(GL_ALPHA_TEST);
|
|
}
|
|
|
|
int Gui::getSlotIdAt(int x, int y) {
|
|
int screenWidth = (int)(minecraft->width * InvGuiScale);
|
|
int screenHeight = (int)(minecraft->height * InvGuiScale);
|
|
x = (int)(x * InvGuiScale);
|
|
y = (int)(y * InvGuiScale);
|
|
|
|
if (y < (screenHeight - 16 - 3) || y > screenHeight)
|
|
return -1;
|
|
|
|
int xBase = 2 + screenWidth / 2 - getNumSlots() * 10;
|
|
int xRel = (x - xBase);
|
|
if (xRel < 0)
|
|
return -1;
|
|
|
|
int slot = xRel / 20;
|
|
return (slot >= 0 && slot < getNumSlots())? slot : -1;
|
|
}
|
|
|
|
bool Gui::isInside(int x, int y) {
|
|
return getSlotIdAt(x, y) != -1;
|
|
}
|
|
|
|
int Gui::getNumSlots() {
|
|
return _numSlots;
|
|
}
|
|
|
|
void Gui::flashSlot(int slotId) {
|
|
_flashSlotId = slotId;
|
|
_flashSlotStartTime = getTimeS();
|
|
}
|
|
|
|
void Gui::getSlotPos(int slot, int& posX, int& posY) {
|
|
int screenWidth = (int)(minecraft->width * InvGuiScale);
|
|
int screenHeight = (int)(minecraft->height * InvGuiScale);
|
|
posX = screenWidth / 2 - getNumSlots() * 10 + slot * 20,
|
|
posY = screenHeight - 22;
|
|
}
|
|
|
|
RectangleArea Gui::getRectangleArea(int extendSide) {
|
|
const int Spacing = 3;
|
|
const float pCenterX = 2.0f + (float)(minecraft->width / 2);
|
|
const float pHalfWidth = (1.0f + (getNumSlots() * 10 + Spacing)) * Gui::GuiScale;
|
|
const float pHeight = (22 + Spacing) * Gui::GuiScale;
|
|
|
|
if (extendSide < 0)
|
|
return RectangleArea(0, (float)minecraft->height-pHeight, pCenterX+pHalfWidth+2, (float)minecraft->height);
|
|
if (extendSide > 0)
|
|
return RectangleArea(pCenterX-pHalfWidth, (float)minecraft->height-pHeight, (float)minecraft->width, (float)minecraft->height);
|
|
|
|
return RectangleArea(pCenterX-pHalfWidth, (float)minecraft->height-pHeight, pCenterX+pHalfWidth+2, (float)minecraft->height);
|
|
}
|
|
|
|
void Gui::handleClick(int button, int x, int y) {
|
|
if (button != MouseAction::ACTION_LEFT) return;
|
|
|
|
int slot = getSlotIdAt(x, y);
|
|
if (slot != -1) {
|
|
if (_openInventorySlot && slot == (getNumSlots()-1)) {
|
|
minecraft->screenChooser.setScreen(SCREEN_BLOCKSELECTION);
|
|
} else {
|
|
minecraft->player->inventory->selectSlot(slot);
|
|
itemNameOverlayTime = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Gui::handleKeyPressed(int key)
|
|
{
|
|
bool isChatting = (minecraft->screen && (dynamic_cast<ChatScreen*>(minecraft->screen) || dynamic_cast<ConsoleScreen*>(minecraft->screen)));
|
|
if (isChatting) {
|
|
// Allow scrolling the chat history with the mouse/keyboard when chat is open
|
|
if (key == 38) { // VK_UP
|
|
scrollChat(1);
|
|
return;
|
|
} else if (key == 40) { // VK_DOWN
|
|
scrollChat(-1);
|
|
return;
|
|
} else if (key == 33) { // VK_PRIOR (Page Up)
|
|
// Scroll by a page
|
|
int screenHeight = (int)(minecraft->height * InvGuiScale);
|
|
int maxVisible = (screenHeight - 48) / 9;
|
|
scrollChat(maxVisible);
|
|
return;
|
|
} else if (key == 34) { // VK_NEXT (Page Down)
|
|
int screenHeight = (int)(minecraft->height * InvGuiScale);
|
|
int maxVisible = (screenHeight - 48) / 9;
|
|
scrollChat(-maxVisible);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (key == Keyboard::KEY_F1) {
|
|
minecraft->options.toggle(OPTIONS_HIDEGUI);
|
|
}
|
|
|
|
if (key == 99)
|
|
{
|
|
if (minecraft->player->inventory->selected > 0)
|
|
{
|
|
minecraft->player->inventory->selected--;
|
|
}
|
|
}
|
|
else if (key == 4)
|
|
{
|
|
if (minecraft->player->inventory->selected < (getNumSlots() - 2))
|
|
{
|
|
minecraft->player->inventory->selected++;
|
|
}
|
|
}
|
|
else if (key == 100)
|
|
{
|
|
minecraft->screenChooser.setScreen(SCREEN_BLOCKSELECTION);
|
|
}
|
|
else if (key == minecraft->options.getIntValue(OPTIONS_KEY_DROP))
|
|
{
|
|
minecraft->player->inventory->dropSlot(minecraft->player->inventory->selected, false);
|
|
}
|
|
}
|
|
|
|
void Gui::scrollChat(int delta) {
|
|
if (delta == 0)
|
|
return;
|
|
|
|
int screenHeight = (int)(minecraft->height * InvGuiScale);
|
|
int maxVisible = (screenHeight - 48) / 9;
|
|
if (maxVisible <= 0)
|
|
return;
|
|
|
|
int maxScroll = (int)guiMessages.size() - maxVisible;
|
|
if (maxScroll < 0) maxScroll = 0;
|
|
int desired = chatScrollOffset + delta;
|
|
if (desired < 0) desired = 0;
|
|
if (desired > maxScroll) desired = maxScroll;
|
|
chatScrollOffset = desired;
|
|
}
|
|
|
|
void Gui::tick() {
|
|
if (overlayMessageTime > 0) overlayMessageTime--;
|
|
tickCount++;
|
|
if(itemNameOverlayTime < 2)
|
|
itemNameOverlayTime += 1.0f / SharedConstants::TicksPerSecond;
|
|
for (unsigned int i = 0; i < guiMessages.size(); i++) {
|
|
guiMessages.at(i).ticks++;
|
|
}
|
|
|
|
if (!minecraft->isCreativeMode())
|
|
tickItemDrop();
|
|
}
|
|
|
|
void Gui::addMessage(const std::string& _string) {
|
|
if (!minecraft->font)
|
|
return;
|
|
|
|
std::string string = _string;
|
|
while (minecraft->font->width(string) > MAX_MESSAGE_WIDTH) {
|
|
unsigned int i = 1;
|
|
while (i < string.length() && minecraft->font->width(string.substr(0, i + 1)) <= MAX_MESSAGE_WIDTH) {
|
|
i++;
|
|
}
|
|
addMessage(string.substr(0, i));
|
|
string = string.substr(i);
|
|
}
|
|
GuiMessage message;
|
|
message.message = string;
|
|
message.ticks = 0;
|
|
guiMessages.insert(guiMessages.begin(), message);
|
|
|
|
// Keep a larger history so users can scroll through the full chat
|
|
const unsigned int MaxHistoryLines = 200;
|
|
while (guiMessages.size() > MaxHistoryLines) {
|
|
guiMessages.pop_back();
|
|
}
|
|
|
|
// If the user has scrolled up, keep their window fixed (new messages shift older ones down)
|
|
if (chatScrollOffset > 0) {
|
|
chatScrollOffset++;
|
|
}
|
|
}
|
|
|
|
void Gui::clearMessages() {
|
|
guiMessages.clear();
|
|
chatScrollOffset = 0;
|
|
}
|
|
|
|
void Gui::setNowPlaying(const std::string& string) {
|
|
overlayMessageString = "Now playing: " + string;
|
|
overlayMessageTime = 20 * 3;
|
|
animateOverlayMessageColor = true;
|
|
}
|
|
|
|
void Gui::displayClientMessage(const std::string& messageId) {
|
|
//Language language = Language.getInstance();
|
|
//std::string languageString = language.getElement(messageId);
|
|
addMessage(messageId);
|
|
}
|
|
|
|
|
|
// @todo - shredder: Function seems to be completely fine and ported over from java beta, but renders opaque??? need to investigate
|
|
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;
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDepthMask(false);
|
|
glBlendFunc2(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
|
|
glColor4f2(tbr, tbr, tbr, 1);
|
|
|
|
minecraft->textures->loadAndBindTexture("misc/vignette.png");
|
|
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
Tesselator& t = Tesselator::instance;
|
|
t.begin();
|
|
t.vertexUV(0, (float)h, -90, 0, 1);
|
|
t.vertexUV((float)w, (float)h, -90, 1, 1);
|
|
t.vertexUV((float)w, 0, -90, 1, 0);
|
|
t.vertexUV(0, 0, -90, 0, 0);
|
|
t.draw();
|
|
glDepthMask(true);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glColor4f2(1, 1, 1, 1);
|
|
glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
|
|
void Gui::renderSlot(int slot, int x, int y, float a) {
|
|
ItemInstance* item = minecraft->player->inventory->getItem(slot);
|
|
|
|
if (!item) {
|
|
//LOGW("Warning: item @ Gui::renderSlot is NULL\n");
|
|
return;
|
|
}
|
|
|
|
const bool fancy = true;
|
|
ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, (float)x, (float)y, fancy);
|
|
}
|
|
|
|
void Gui::renderSlotText( const ItemInstance* item, float x, float y, bool hasFinite, bool shadow )
|
|
{
|
|
//if (!item || item->getItem()->getMaxStackSize() <= 1) {
|
|
if (item->count <= 1) {
|
|
return;
|
|
}
|
|
|
|
int c = item->count;
|
|
|
|
char buffer[4] = {0,0,0,0};
|
|
if (hasFinite)
|
|
itemCountItoa(buffer, c);
|
|
else
|
|
buffer[0] = (char)157;
|
|
|
|
//LOGI("slot: %d - %s\n", slot, buffer);
|
|
if (shadow)
|
|
minecraft->font->drawShadow(buffer, x, y, item->count>0?0xffcccccc:0x60cccccc);
|
|
else
|
|
minecraft->font->draw(buffer, x, y, item->count>0?0xffcccccc:0x60cccccc);
|
|
}
|
|
|
|
void Gui::inventoryUpdated() {
|
|
_inventoryNeedsUpdate = true;
|
|
}
|
|
|
|
void Gui::onGraphicsReset() {
|
|
inventoryUpdated();
|
|
}
|
|
|
|
void Gui::texturesLoaded( Textures* textures ) {
|
|
//_slotFont = new Font(&minecraft->options, "gui/gui_blocks.png", textures, 0, 504, 10, 1, '0');
|
|
}
|
|
|
|
void Gui::onConfigChanged( const Config& c ) {
|
|
Tesselator& t = Tesselator::instance;
|
|
t.begin();
|
|
|
|
//
|
|
// Create outer feedback circle
|
|
//
|
|
#ifdef ANDROID
|
|
const float mm = 50; //20
|
|
#else
|
|
const float mm = 50; //20
|
|
#endif
|
|
const float maxRadius = minecraft->pixelCalcUi.millimetersToPixels(mm);
|
|
const float radius = Mth::Min(80.0f/2, maxRadius);
|
|
//LOGI("radius, maxradius: %f, %f\n", radius, maxRadius);
|
|
const float radiusInner = radius * 0.95f;
|
|
|
|
const int steps = 24;
|
|
const float fstep = Mth::TWO_PI / steps;
|
|
for (int i = 0; i < steps; ++i) {
|
|
float a = i * fstep;;
|
|
float b = a + fstep;
|
|
|
|
float aCos = Mth::cos(a);
|
|
float bCos = Mth::cos(b);
|
|
float aSin = Mth::sin(a);
|
|
float bSin = Mth::sin(b);
|
|
float x00 = radius * aCos;
|
|
float x01 = radiusInner * aCos;
|
|
float x10 = radius * bCos;
|
|
float x11 = radiusInner * bCos;
|
|
float y00 = radius * aSin;
|
|
float y01 = radiusInner * aSin;
|
|
float y10 = radius * bSin;
|
|
float y11 = radiusInner * bSin;
|
|
|
|
t.vertexUV(x01, y01, 0, 0, 1);
|
|
t.vertexUV(x11, y11, 0, 1, 1);
|
|
t.vertexUV(x10, y10, 0, 1, 0);
|
|
t.vertexUV(x00, y00, 0, 0, 0);
|
|
}
|
|
rcFeedbackOuter = t.end(true, rcFeedbackOuter.vboId);
|
|
|
|
//
|
|
// Create the inner feedback ring
|
|
//
|
|
t.begin(GL_TRIANGLE_FAN);
|
|
t.vertex(0, 0, 0);
|
|
for (int i = 0; i < steps + 1; ++i) {
|
|
float a = -i * fstep;
|
|
float xx = radiusInner * Mth::cos(a);
|
|
float yy = radiusInner * Mth::sin(a);
|
|
t.vertex(xx, yy, 0);
|
|
//LOGI("x,y: %f, %f\n", xx, yy);
|
|
}
|
|
rcFeedbackInner = t.end(true, rcFeedbackInner.vboId);
|
|
|
|
if (c.minecraft->useTouchscreen()) {
|
|
// I'll bump this up to 6.
|
|
int num = 6; // without "..." dots
|
|
if (!c.minecraft->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA) && c.width > 480) {
|
|
while (num < Inventory::MAX_SELECTION_SIZE - 1) {
|
|
int x0, x1, y;
|
|
getSlotPos(0, x0, y);
|
|
getSlotPos(num, x1, y);
|
|
int width = x1 - x0;
|
|
float leftoverPixels = c.width - c.guiScale*width;
|
|
if (c.pixelCalc.pixelsToMillimeters(leftoverPixels) < 80)
|
|
break;
|
|
num++;
|
|
}
|
|
}
|
|
_numSlots = num;
|
|
#if defined(__APPLE__)
|
|
_numSlots = Mth::Min(7, _numSlots);
|
|
#endif
|
|
} else {
|
|
_numSlots = Inventory::MAX_SELECTION_SIZE; // Xperia Play
|
|
}
|
|
MAX_MESSAGE_WIDTH = c.guiWidth;
|
|
}
|
|
|
|
float Gui::floorAlignToScreenPixel(float v) {
|
|
return (int)(v * Gui::GuiScale) * Gui::InvGuiScale;
|
|
}
|
|
|
|
int Gui::itemCountItoa( char* buffer, int count )
|
|
{
|
|
if (count < 0)
|
|
return 0;
|
|
|
|
if (count < 10) { // 1 digit
|
|
buffer[0] = '0' + count;
|
|
buffer[1] = 0;
|
|
return 1;
|
|
} else if (count < 100) { // 2 digits
|
|
int digit = count/10;
|
|
buffer[0] = '0' + digit;
|
|
buffer[1] = '0' + count - digit*10;
|
|
buffer[2] = 0;
|
|
} else { // 3 digits -> "99+"
|
|
buffer[0] = buffer[1] = '9';
|
|
buffer[2] = '+';
|
|
buffer[3] = 0;
|
|
return 3;
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
void Gui::tickItemDrop()
|
|
{
|
|
// Handle item drop
|
|
static bool isCurrentlyActive = false;
|
|
isCurrentlyActive = false;
|
|
|
|
int slots = getNumSlots() - _openInventorySlot;
|
|
|
|
if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) {
|
|
int slot = getSlotIdAt(Mouse::getX(), Mouse::getY());
|
|
if (slot >= 0 && slot < slots) {
|
|
if (slot != _currentDropSlot) {
|
|
_currentDropTicks = 0;
|
|
_currentDropSlot = slot;
|
|
}
|
|
isCurrentlyActive = true;
|
|
if ((_currentDropTicks += 1.0f) >= DropTicks) {
|
|
minecraft->player->inventory->dropSlot(slot, false);
|
|
minecraft->level->playSound(minecraft->player, "random.pop", 0.3f, 1);
|
|
isCurrentlyActive = false;
|
|
}
|
|
}
|
|
}
|
|
if (!isCurrentlyActive) {
|
|
_currentDropSlot = -1;
|
|
_currentDropTicks = -1;
|
|
}
|
|
}
|
|
|
|
void Gui::postError( int errCode )
|
|
{
|
|
static std::set<int> posted;
|
|
if (posted.find(errCode) != posted.end())
|
|
return;
|
|
|
|
posted.insert(errCode);
|
|
|
|
std::stringstream s;
|
|
s << "Something went wrong! (errcode " << errCode << ")\n";
|
|
addMessage(s.str());
|
|
}
|
|
|
|
void Gui::setScissorRect( const IntRectangle& bbox )
|
|
{
|
|
GLuint x = (GLuint)(GuiScale * bbox.x);
|
|
GLuint y = minecraft->height - (GLuint)(GuiScale * (bbox.y + bbox.h));
|
|
GLuint w = (GLuint)(GuiScale * bbox.w);
|
|
GLuint h = (GLuint)(GuiScale * bbox.h);
|
|
glScissor(x, y, w, h);
|
|
}
|
|
|
|
float Gui::cubeSmoothStep(float percentage, float min, float max) {
|
|
//percentage = percentage * percentage;
|
|
//return (min * percentage) + (max * (1 - percentage));
|
|
return (percentage) * (percentage) * (3 - 2 * (percentage));
|
|
}
|
|
|
|
void Gui::renderProgressIndicator( const bool isTouchInterface, const int screenWidth, const int screenHeight, float a ) {
|
|
ItemInstance* currentItem = minecraft->player->inventory->getSelected();
|
|
bool bowEquipped = currentItem != NULL ? currentItem->getItem() == Item::bow : false;
|
|
bool itemInUse = currentItem != NULL ? currentItem->getItem() == minecraft->player->getUseItem()->getItem() : false;
|
|
//if ((!isTouchInterface || minecraft->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA)
|
|
// || (bowEquipped && itemInUse)) && !minecraft->options.getBooleanValue(OPTIONS_HIDEGUI))
|
|
if ((!isTouchInterface || minecraft->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA)
|
|
|| (bowEquipped && itemInUse)) && !minecraft->options.getBooleanValue(OPTIONS_HIDEGUI))
|
|
{
|
|
minecraft->textures->loadAndBindTexture("gui/icons.png");
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc2(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
|
|
blit(screenWidth/2 - 8, screenHeight/2 - 8, 0, 0, 16, 16);
|
|
glDisable(GL_BLEND);
|
|
} else if(!bowEquipped) {
|
|
const float tprogress = minecraft->gameMode->destroyProgress;
|
|
const float alpha = Mth::clamp(minecraft->inputHolder->alpha, 0.0f, 1.0f);
|
|
//LOGI("alpha: %f\n", alpha);
|
|
|
|
if (tprogress <= 0 && minecraft->inputHolder->alpha >= 0) {
|
|
glDisable2(GL_TEXTURE_2D);
|
|
glEnable2(GL_BLEND);
|
|
glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
if (minecraft->hitResult.isHit())
|
|
glColor4f2(1, 1, 1, 0.8f * alpha);
|
|
else
|
|
glColor4f2(1, 1, 1, Mth::Min(0.4f, alpha*0.4f));
|
|
|
|
//LOGI("alpha2: %f\n", alpha);
|
|
const float x = InvGuiScale * minecraft->inputHolder->mousex;
|
|
const float y = InvGuiScale * minecraft->inputHolder->mousey;
|
|
glTranslatef2(x, y, 0);
|
|
drawArrayVT(rcFeedbackOuter.vboId, rcFeedbackOuter.vertexCount, 24);
|
|
glTranslatef2(-x, -y, 0);
|
|
|
|
glEnable2(GL_TEXTURE_2D);
|
|
glDisable(GL_BLEND);
|
|
} else if (tprogress > 0) {
|
|
const float oProgress = minecraft->gameMode->oDestroyProgress;
|
|
const float progress = 0.5f * (oProgress + (tprogress - oProgress) * a);
|
|
|
|
//static Stopwatch w;
|
|
//w.start();
|
|
|
|
glDisable2(GL_TEXTURE_2D);
|
|
glColor4f2(1, 1, 1, 0.8f * alpha);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
const float x = InvGuiScale * minecraft->inputHolder->mousex;
|
|
const float y = InvGuiScale * minecraft->inputHolder->mousey;
|
|
glPushMatrix2();
|
|
glTranslatef2(x, y, 0);
|
|
drawArrayVT(rcFeedbackOuter.vboId, rcFeedbackOuter.vertexCount, 24);
|
|
glScalef2(0.5f + progress, 0.5f + progress, 1);
|
|
//glDisable2(GL_CULL_FACE);
|
|
glColor4f2(1, 1, 1, 1);
|
|
glBlendFunc2(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
|
|
drawArrayVT(rcFeedbackInner.vboId, rcFeedbackInner.vertexCount, 24, GL_TRIANGLE_FAN);
|
|
glPopMatrix2();
|
|
|
|
glDisable(GL_BLEND);
|
|
glEnable2(GL_TEXTURE_2D);
|
|
|
|
//w.stop();
|
|
//w.printEvery(100, "feedback-r ");
|
|
}
|
|
}
|
|
}
|
|
|
|
void Gui::renderHearts() {
|
|
bool blink = (minecraft->player->invulnerableTime / 3) % 2 == 1;
|
|
if (minecraft->player->invulnerableTime < 10) blink = false;
|
|
int h = minecraft->player->health;
|
|
int oh = minecraft->player->lastHealth;
|
|
random.setSeed(tickCount * 312871);
|
|
|
|
int screenWidth = (int)(minecraft->width * InvGuiScale);
|
|
int screenHeight = (int)(minecraft->height * InvGuiScale);
|
|
|
|
int xx = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenWidth / 2 - getNumSlots() * 10 - 1 : 2;
|
|
|
|
int armor = minecraft->player->getArmorValue();
|
|
for (int i = 0; i < Player::MAX_HEALTH / 2; i++) {
|
|
int yo = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenHeight - 32 : 2;
|
|
int ip2 = i + i + 1;
|
|
|
|
if (armor > 0) {
|
|
int xo = xx + 80 + i * 8 + 4;
|
|
if (ip2 < armor) blit(xo, yo, 16 + 2 * 9, 9 * 1, 9, 9);
|
|
else if (ip2 == armor) blit(xo, yo, 16 + 4 * 9, 9 * 1, 9, 9);
|
|
else if (ip2 > armor) blit(xo, yo, 16 + 0 * 9, 9 * 1, 9, 9);
|
|
}
|
|
|
|
int bg = 0;
|
|
if (blink) bg = 1;
|
|
int xo = xx + i * 8;
|
|
if (h <= 4) {
|
|
yo = yo + random.nextInt(2) - 1;
|
|
}
|
|
blit(xo, yo, 16 + bg * 9, 9 * 0, 9, 9);
|
|
if (blink) {
|
|
if (ip2 < oh) blit(xo, yo, 16 + 6 * 9, 9 * 0, 9, 9);
|
|
else if (ip2 == oh) blit(xo, yo, 16 + 7 * 9, 9 * 0, 9, 9);
|
|
}
|
|
if (ip2 < h) blit(xo, yo, 16 + 4 * 9, 9 * 0, 9, 9);
|
|
else if (ip2 == h) blit(xo, yo, 16 + 5 * 9, 9 * 0, 9, 9);
|
|
}
|
|
}
|
|
|
|
void Gui::renderBubbles() {
|
|
if (minecraft->player->isUnderLiquid(Material::water)) {
|
|
int screenWidth = (int)(minecraft->width * InvGuiScale);
|
|
int screenHeight = (int)(minecraft->height * InvGuiScale);
|
|
|
|
int xx = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenWidth / 2 - getNumSlots() * 10 - 1 : 2;
|
|
int yo = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenHeight - 42 : 12;
|
|
int count = (int) std::ceil((minecraft->player->airSupply - 2) * 10.0f / Player::TOTAL_AIR_SUPPLY);
|
|
int extra = (int) std::ceil((minecraft->player->airSupply) * 10.0f / Player::TOTAL_AIR_SUPPLY) - count;
|
|
for (int i = 0; i < count + extra; i++) {
|
|
int xo = i * 8 + xx;
|
|
if (i < count) blit(xo, yo, 16, 9 * 2, 9, 9);
|
|
else blit(xo, yo, 16 + 9, 9 * 2, 9, 9);
|
|
}
|
|
}
|
|
}
|
|
|
|
static OffsetPosTranslator posTranslator;
|
|
void Gui::onLevelGenerated() {
|
|
if (Level* level = minecraft->level) {
|
|
Pos p = level->getSharedSpawnPos();
|
|
posTranslator = OffsetPosTranslator((float)-p.x, (float)-p.y, (float)-p.z);
|
|
}
|
|
}
|
|
|
|
void Gui::renderDebugInfo() {
|
|
// FPS counter (updates once per second)
|
|
static float fps = 0.0f;
|
|
static float fpsLastTime = 0.0f;
|
|
static int fpsFrames = 0;
|
|
float now = getTimeS();
|
|
fpsFrames++;
|
|
if (now - fpsLastTime >= 1.0f) {
|
|
fps = fpsFrames / (now - fpsLastTime);
|
|
fpsFrames = 0;
|
|
fpsLastTime = now;
|
|
}
|
|
|
|
LocalPlayer* p = minecraft->player;
|
|
Level* lvl = minecraft->level;
|
|
|
|
// Position
|
|
float px = p->x, py = p->y - p->heightOffset, pz = p->z;
|
|
posTranslator.to(px, py, pz);
|
|
int bx = (int)floorf(px), by = (int)floorf(py), bz = (int)floorf(pz);
|
|
int cx = bx >> 4, cz = bz >> 4;
|
|
|
|
// Facing direction
|
|
float yMod = fmodf(p->yRot, 360.0f);
|
|
if (yMod < 0) yMod += 360.0f;
|
|
const char* facing;
|
|
const char* axis;
|
|
if (yMod < 45 || yMod >= 315) { facing = "South"; axis = "+Z"; }
|
|
else if (yMod < 135) { facing = "West"; axis = "-X"; }
|
|
else if (yMod < 225) { facing = "North"; axis = "-Z"; }
|
|
else { facing = "East"; axis = "+X"; }
|
|
|
|
// Biome
|
|
const char* biomeName = "unknown";
|
|
if (lvl) {
|
|
Biome* biome = lvl->getBiome(bx, bz);
|
|
if (biome) biomeName = biome->name.c_str();
|
|
}
|
|
|
|
// Time
|
|
long worldTime = lvl ? lvl->getTime() : 0;
|
|
long dayTime = worldTime % Level::TICKS_PER_DAY;
|
|
long day = worldTime / Level::TICKS_PER_DAY;
|
|
long seed = lvl ? lvl->getSeed() : 0;
|
|
|
|
// Build lines (NULL entry = blank gap)
|
|
static char ln[8][96];
|
|
sprintf(ln[0], "Minecraft PE 0.6.1 alpha (mcpe64)");
|
|
sprintf(ln[1], "%.1f fps", fps);
|
|
ln[2][0] = '\0'; // blank separator
|
|
sprintf(ln[3], "XYZ: %.3f / %.3f / %.3f", px, py, pz);
|
|
sprintf(ln[4], "Block: %d %d %d Chunk: %d %d", bx, by, bz, cx, cz);
|
|
sprintf(ln[5], "Facing: %s (%s) (%.1f / %.1f)", facing, axis, p->yRot, p->xRot);
|
|
sprintf(ln[6], "Biome: %s", biomeName);
|
|
sprintf(ln[7], "Day %ld Time: %ld Seed: %ld", day, dayTime, seed);
|
|
|
|
const int N = 8;
|
|
const float LH = (float)Font::DefaultLineHeight; // 10 font-pixels
|
|
const float MGN = 2.0f; // left/top margin in font-pixels
|
|
const float PAD = 2.0f; // horizontal padding for background
|
|
Font* font = minecraft->font;
|
|
|
|
// 1) Draw semi-transparent background boxes behind each line
|
|
for (int i = 0; i < N; i++) {
|
|
if (ln[i][0] == '\0') continue;
|
|
float w = (float)font->width(ln[i]);
|
|
float x0 = MGN - PAD;
|
|
float y0 = MGN + i * LH - 1.0f;
|
|
float x1 = MGN + w + PAD;
|
|
float y1 = MGN + (i + 1) * LH - 1.0f;
|
|
fill(x0, y0, x1, y1, 0x90000000);
|
|
}
|
|
|
|
// 2) Draw text (no extra scale — font coords are in GUI units, same as fill)
|
|
Tesselator& t = Tesselator::instance;
|
|
t.beginOverride();
|
|
for (int i = 0; i < N; i++) {
|
|
if (ln[i][0] == '\0') continue;
|
|
float y = MGN + i * LH;
|
|
int col = (i == 0) ? 0xffFFFF55 : 0xffffffff; // title yellow, rest white
|
|
font->draw(ln[i], MGN, y, col);
|
|
}
|
|
t.endOverrideAndDraw();
|
|
}
|
|
|
|
void Gui::renderPlayerList(Font* font, int screenWidth, int screenHeight) {
|
|
// only show when in game, no other screen
|
|
// if (!minecraft->level) return;
|
|
|
|
// only show the overlay while connected to a multiplayer server
|
|
Level* level = minecraft->level;
|
|
if (!level) return;
|
|
if (!level->isClientSide) return;
|
|
|
|
std::vector<std::string> playerNames;
|
|
playerNames.reserve(level->players.size());
|
|
|
|
for (Player* player : level->players) {
|
|
if (!player) continue;
|
|
playerNames.push_back(player->name);
|
|
}
|
|
|
|
// is this check needed? if there are no players, the box won't render at all since height will be 0,
|
|
// but maybe we want to skip rendering entirely in that case
|
|
// if (playerNames.empty())
|
|
// return;
|
|
|
|
std::sort(playerNames.begin(), playerNames.end());
|
|
|
|
float maxNameWidth = 0.0f;
|
|
// find the longest name so we can size the box accordingly
|
|
for (const std::string& name : playerNames) {
|
|
float nameWidth = font->width(name);
|
|
if (nameWidth > maxNameWidth)
|
|
maxNameWidth = nameWidth;
|
|
}
|
|
|
|
// player count title
|
|
std::ostringstream titleStream;
|
|
titleStream << "Players (" << playerNames.size() << ")";
|
|
std::string titleText = titleStream.str();
|
|
float titleWidth = font->width(titleText);
|
|
|
|
if (titleWidth > maxNameWidth)
|
|
maxNameWidth = titleWidth;
|
|
|
|
const float padding = 4.0f;
|
|
const float lineHeight = (float)Font::DefaultLineHeight;
|
|
|
|
const float boxWidth = maxNameWidth + padding * 2;
|
|
const float boxHeight = (playerNames.size() + 1) * lineHeight + padding * 2;
|
|
|
|
const float boxLeft = (screenWidth - boxWidth) / 2.0f;
|
|
const float boxTop = 10.0f;
|
|
const float boxRight = boxLeft + boxWidth;
|
|
const float boxBottom = boxTop + boxHeight;
|
|
|
|
fill(boxLeft, boxTop, boxRight, boxBottom, 0x90000000);
|
|
|
|
float titleX = (screenWidth - titleWidth) / 2.0f;
|
|
float titleY = boxTop + padding;
|
|
|
|
// scale the text down slightly
|
|
// i think the gl scaling is the best for this
|
|
// oh my god this looks really bad OH GOD
|
|
//const float textScale = 0.8f;
|
|
//const float invTextScale = 1.0f / textScale;
|
|
//glPushMatrix2();
|
|
//glScalef2(textScale, textScale, 1);
|
|
|
|
// draw title
|
|
//font->draw(titleText, titleX * invTextScale, titleY * invTextScale, 0xFFFFFFFF);
|
|
font->draw(titleText, titleX, titleY, 0xFFFFFFFF);
|
|
|
|
// draw player names
|
|
// we should add ping icons here eventually, but for now just show names
|
|
float currentY = boxTop + padding + lineHeight;
|
|
for (const std::string& name : playerNames) {
|
|
font->draw(name, (boxLeft + padding), currentY, 0xFFDDDDDD);
|
|
currentY += lineHeight;
|
|
}
|
|
//glPopMatrix2();
|
|
}
|
|
|
|
void Gui::renderSleepAnimation( const int screenWidth, const int screenHeight ) {
|
|
int timer = minecraft->player->getSleepTimer();
|
|
float amount = (float) timer / (float) Player::SLEEP_DURATION;
|
|
if (amount > 1) {
|
|
// waking up
|
|
amount = 1.0f - ((float) (timer - Player::SLEEP_DURATION) / (float) Player::WAKE_UP_DURATION);
|
|
}
|
|
|
|
int color = (int) (220.0f * amount) << 24 | (0x101020);
|
|
fill(0, 0, screenWidth, screenHeight, color);
|
|
}
|
|
|
|
void Gui::renderOnSelectItemNameText( const int screenWidth, Font* font, int ySlot ) {
|
|
if(itemNameOverlayTime < 1.0f) {
|
|
ItemInstance* item = minecraft->player->inventory->getSelected();
|
|
if(item != NULL) {
|
|
float x = float(screenWidth / 2 - font->width(item->getName()) / 2);
|
|
float y = float(ySlot - 22);
|
|
int alpha = 255;
|
|
if(itemNameOverlayTime > 0.75) {
|
|
float time = 0.25f - (itemNameOverlayTime - 0.75f);
|
|
float percentage = cubeSmoothStep(time * 4, 0.0f, 1.0f);
|
|
alpha = int(percentage * 255);
|
|
}
|
|
if(alpha != 0)
|
|
font->drawShadow(item->getName(), x, y, 0x00ffffff + (alpha << 24));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// helper structure used by drawColoredString
|
|
struct ColorSegment {
|
|
std::string text;
|
|
uint32_t color;
|
|
};
|
|
|
|
// parse [tag] and [/tag] markers; tags may contain a color name (gold, green, etc.)
|
|
static void parseColorTags(const std::string& in, std::vector<ColorSegment>& out) {
|
|
uint32_t curColor = 0xffffff;
|
|
size_t pos = 0;
|
|
while (pos < in.size()) {
|
|
size_t open = in.find('[', pos);
|
|
if (open == std::string::npos) {
|
|
out.push_back({in.substr(pos), curColor});
|
|
break;
|
|
}
|
|
if (open > pos) {
|
|
out.push_back({in.substr(pos, open - pos), curColor});
|
|
}
|
|
size_t close = in.find(']', open);
|
|
if (close == std::string::npos) {
|
|
out.push_back({in.substr(open), curColor});
|
|
break;
|
|
}
|
|
std::string tag = in.substr(open + 1, close - open - 1);
|
|
if (!tag.empty() && tag[0] == '/') {
|
|
curColor = 0xffffff;
|
|
} else {
|
|
std::string lower;
|
|
lower.resize(tag.size());
|
|
std::transform(tag.begin(), tag.end(), lower.begin(), ::tolower);
|
|
if (lower.find("gold") != std::string::npos) curColor = 0xffd700;
|
|
else if (lower.find("green") != std::string::npos) curColor = 0x00ff00;
|
|
else if (lower.find("yellow") != std::string::npos) curColor = 0xffff00;
|
|
else if (lower.find("red") != std::string::npos) curColor = 0xff0000;
|
|
else if (lower.find("blue") != std::string::npos) curColor = 0x0000ff;
|
|
}
|
|
pos = close + 1;
|
|
}
|
|
}
|
|
|
|
void Gui::drawColoredString(Font* font, const std::string& text, float x, float y, int alpha) {
|
|
std::vector<ColorSegment> segs;
|
|
parseColorTags(text, segs);
|
|
float cx = x;
|
|
for (auto &s : segs) {
|
|
int color = s.color + (alpha << 24);
|
|
font->drawShadow(s.text, cx, y, color);
|
|
cx += font->width(s.text);
|
|
}
|
|
}
|
|
|
|
float Gui::getColoredWidth(Font* font, const std::string& text) {
|
|
std::vector<ColorSegment> segs;
|
|
parseColorTags(text, segs);
|
|
float w = 0;
|
|
for (auto &s : segs) {
|
|
w += font->width(s.text);
|
|
}
|
|
return w;
|
|
}
|
|
|
|
void Gui::renderChatMessages( const int screenHeight, unsigned int max, bool isChatting, Font* font ) {
|
|
// if (minecraft.screen instanceof ChatScreen) {
|
|
// max = 20;
|
|
// isChatting = true;
|
|
// }
|
|
//
|
|
// glEnable(GL_BLEND);
|
|
// glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
// glDisable(GL_ALPHA_TEST);
|
|
//
|
|
// glPushMatrix2();
|
|
// glTranslatef2(0, screenHeight - 48, 0);
|
|
// // glScalef2(1.0f / ssc.scale, 1.0f / ssc.scale, 1);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
int baseY = screenHeight - 48;
|
|
int start = chatScrollOffset;
|
|
if (start < 0) start = 0;
|
|
for (unsigned int i = 0; i < max; i++) {
|
|
unsigned int msgIdx = (unsigned int)start + i;
|
|
if (msgIdx >= guiMessages.size())
|
|
break;
|
|
|
|
GuiMessage& message = guiMessages.at(msgIdx);
|
|
if (message.ticks < 20 * 10 || isChatting) {
|
|
float t = message.ticks / (20 * 10.0f);
|
|
t = 1 - t;
|
|
t = t * 10;
|
|
if (t < 0) t = 0;
|
|
if (t > 1) t = 1;
|
|
t = t * t;
|
|
int alpha = (int) (255 * t);
|
|
if (isChatting) alpha = 255;
|
|
|
|
if (alpha > 0) {
|
|
const float x = 2;
|
|
const float y = (float)(baseY - i * 9);
|
|
std::string msg = message.message;
|
|
this->fill(x, y - 1, x + MAX_MESSAGE_WIDTH, y + 8, (alpha / 2) << 24);
|
|
glEnable(GL_BLEND);
|
|
|
|
// special-case join/leave announcements
|
|
int baseColor = 0xffffff;
|
|
if (msg.find(" joined the game") != std::string::npos ||
|
|
msg.find(" left the game") != std::string::npos) {
|
|
baseColor = 0xffff00; // yellow
|
|
}
|
|
// replace previous logic; allow full colour tags now
|
|
Gui::drawColoredString(font, msg, x, y, alpha);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Gui::renderToolBar( float a, int ySlot, const int screenWidth ) {
|
|
glColor4f2(1, 1, 1, 1);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
minecraft->textures->loadAndBindTexture("gui/gui.png");
|
|
|
|
Inventory* inventory = minecraft->player->inventory;
|
|
|
|
int xBase, yBase;
|
|
getSlotPos(0, xBase, yBase);
|
|
const float baseItemX = (float)xBase + 3;
|
|
const int slotsWidth = 20 * getNumSlots();
|
|
// Left + right side of the selection bar
|
|
blit(xBase, yBase, 0, 0, slotsWidth, 22);
|
|
blit(xBase + slotsWidth, yBase, 180, 0, 2, 22);
|
|
|
|
if (_currentDropSlot >= 0 && inventory->getItem(_currentDropSlot)) {
|
|
int x = xBase + 3 + _currentDropSlot * 20;
|
|
int color = 0x8000ff00;
|
|
int yy = (int)(17.0f * (_currentDropTicks + a) / DropTicks);
|
|
|
|
if (_currentDropTicks >= 3) {
|
|
glColor4f2(0, 1, 0, 0.5f);
|
|
}
|
|
fill(x, ySlot+16-yy, x+16, ySlot+16, color);
|
|
}
|
|
blit(xBase-1 + 20*inventory->selected, yBase - 1, 0, 22, 24, 22);
|
|
glColor4f2(1, 1, 1, 1);
|
|
|
|
// Flash a slot background
|
|
if (_flashSlotId >= 0) {
|
|
const float since = getTimeS() - _flashSlotStartTime;
|
|
if (since > 0.2f) _flashSlotId = -1;
|
|
else {
|
|
int x = screenWidth / 2 - getNumSlots() * 10 + _flashSlotId * 20 + 2;
|
|
int color = 0xffffff + (((int)(/*0x80 * since +*/ 0x51 - 0x50 * Mth::cos(10 * 6.28f * since))) << 24);
|
|
//LOGI("Color: %.8x\n", color);
|
|
fill(x, ySlot, x+16, ySlot+16, color);
|
|
}
|
|
}
|
|
glColor4f2(1, 1, 1, 1);
|
|
|
|
//static Stopwatch w;
|
|
//w.start();
|
|
|
|
Tesselator& t = Tesselator::instance;
|
|
t.beginOverride();
|
|
|
|
float x = baseItemX;
|
|
|
|
int slots = getNumSlots() - _openInventorySlot;
|
|
|
|
for (int i = 0; i < slots; i++) {
|
|
renderSlot(i, (int)x, ySlot, a);
|
|
x += 20;
|
|
}
|
|
_inventoryNeedsUpdate = false;
|
|
|
|
|
|
if (_openInventorySlot) {
|
|
blit(screenWidth / 2 + 10 * getNumSlots() - 20 + 4, ySlot + 6, 242, 252, 14, 4, 14, 4);
|
|
}
|
|
|
|
minecraft->textures->loadAndBindTexture("gui/gui_blocks.png");
|
|
t.endOverrideAndDraw();
|
|
|
|
// Render damaged items (@todo: investigate if it's faster by drawing in same batch)
|
|
glDisable2(GL_DEPTH_TEST);
|
|
glDisable2(GL_TEXTURE_2D);
|
|
t.beginOverride();
|
|
x = baseItemX;
|
|
for (int i = 0; i < slots; i++) {
|
|
ItemRenderer::renderGuiItemDecorations(minecraft->player->inventory->getItem(i), x, (float)ySlot);
|
|
x += 20;
|
|
}
|
|
t.endOverrideAndDraw();
|
|
glEnable(GL_DEPTH_TEST);
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
//w.stop();
|
|
//w.printEvery(100, "gui-slots");
|
|
|
|
// Draw count
|
|
//Tesselator& t = Tesselator::instance;
|
|
|
|
const float k = 0.5f * GuiScale;
|
|
if (minecraft->options.getBooleanValue(OPTIONS_JAVA_HUD)) // if true enables the java beta item count size and color and calls the java items decorations
|
|
{
|
|
t.beginOverride();
|
|
if (minecraft->gameMode->isSurvivalType()) {
|
|
x = baseItemX;
|
|
for (int i = 0; i < slots; i++) {
|
|
ItemInstance* item = minecraft->player->inventory->getItem(i);
|
|
if (item && item->count >= 0)
|
|
ItemRenderer::renderGuiItemDecorations(minecraft->font, minecraft->textures, minecraft->player->inventory->getItem(i), x, (float)ySlot);
|
|
x += 20;
|
|
}
|
|
}
|
|
minecraft->textures->loadAndBindTexture("font/default8.png");
|
|
t.endOverrideAndDraw();
|
|
}
|
|
else { // otherwise uses the normal pocket edition one
|
|
glPushMatrix2();
|
|
glScalef2(InvGuiScale + InvGuiScale, InvGuiScale + InvGuiScale, 1);
|
|
t.beginOverride();
|
|
if (minecraft->gameMode->isSurvivalType()) {
|
|
x = baseItemX;
|
|
for (int i = 0; i < slots; i++) {
|
|
ItemInstance* item = minecraft->player->inventory->getItem(i);
|
|
if (item && item->count >= 0)
|
|
renderSlotText(item, k*x, k*ySlot, true, true);
|
|
x += 20;
|
|
}
|
|
}
|
|
|
|
minecraft->textures->loadAndBindTexture("font/default8.png");
|
|
t.endOverrideAndDraw();
|
|
|
|
glPopMatrix2();
|
|
}
|
|
|
|
}
|