2013-08-29 11:45:22 +09:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 yvt
|
|
|
|
|
|
|
|
This file is part of OpenSpades.
|
|
|
|
|
|
|
|
OpenSpades is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
OpenSpades is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
*/
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
#include "ChatWindow.h"
|
|
|
|
#include "IRenderer.h"
|
|
|
|
#include "IFont.h"
|
|
|
|
#include "../Core/Debug.h"
|
|
|
|
#include "Client.h"
|
|
|
|
#include "World.h"
|
|
|
|
#include "../Core/Exception.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
namespace spades {
|
|
|
|
namespace client{
|
|
|
|
|
2013-08-26 17:53:14 +09:00
|
|
|
ChatWindow::ChatWindow(Client *cli, IFont *fnt,
|
|
|
|
bool killfeed):
|
2013-08-18 16:18:06 +09:00
|
|
|
client(cli), renderer(cli->GetRenderer()),
|
2013-08-26 17:53:14 +09:00
|
|
|
font(fnt), killfeed(killfeed){
|
2013-08-18 16:18:06 +09:00
|
|
|
firstY = 0.f;
|
|
|
|
}
|
|
|
|
ChatWindow::~ChatWindow(){}
|
|
|
|
|
|
|
|
float ChatWindow::GetWidth() {
|
|
|
|
return renderer->ScreenWidth() / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
float ChatWindow::GetHeight() {
|
|
|
|
return renderer->ScreenHeight() / 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
float ChatWindow::GetLineHeight() {
|
|
|
|
return 20.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isWordChar(char c){
|
|
|
|
return isalnum(c) || c == '\'';
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatWindow::AddMessage(const std::string &msg){
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
ChatEntry ent;
|
|
|
|
|
|
|
|
// get visible message string
|
|
|
|
std::string str;
|
|
|
|
float x = 0.f, maxW = GetWidth();
|
|
|
|
float lh = GetLineHeight(), h = lh;
|
|
|
|
size_t wordStart = std::string::npos;
|
|
|
|
size_t wordStartOutPos;
|
|
|
|
|
|
|
|
for(size_t i = 0; i < msg.size(); i++){
|
|
|
|
if(msg[i] > MsgColorMax &&
|
|
|
|
msg[i] != 13 && msg[i] != 10){
|
|
|
|
if(isWordChar(msg[i])){
|
|
|
|
if(wordStart == std::string::npos){
|
|
|
|
wordStart = msg.size();
|
|
|
|
wordStartOutPos = str.size();
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
wordStart = std::string::npos;
|
|
|
|
}
|
|
|
|
|
|
|
|
float w = font->Measure(std::string(&msg[i],1)).x;
|
|
|
|
if(x + w > maxW){
|
|
|
|
if(wordStart != std::string::npos &&
|
|
|
|
wordStart != str.size()){
|
|
|
|
// adding a part of word.
|
|
|
|
// do word wrapping
|
|
|
|
|
|
|
|
std::string s = msg.substr(wordStart, i - wordStart + 1);
|
|
|
|
float nw = font->Measure(s).x;
|
|
|
|
if(nw <= maxW){
|
|
|
|
// word wrap succeeds
|
|
|
|
|
|
|
|
w = nw;
|
|
|
|
x = w;
|
|
|
|
h += lh;
|
|
|
|
str.insert(wordStartOutPos, "\n");
|
|
|
|
|
|
|
|
goto didWordWrap;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
x = 0; h += lh;
|
|
|
|
str += 13;
|
|
|
|
}
|
|
|
|
x += w;
|
|
|
|
str += msg[i];
|
|
|
|
didWordWrap:;
|
|
|
|
}else if(msg[i] == 13 || msg[i] == 10){
|
|
|
|
x = 0; h += lh;
|
|
|
|
str += 13;
|
|
|
|
}else{
|
|
|
|
str += msg[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ent.height = h;
|
|
|
|
ent.msg = msg;
|
|
|
|
ent.fade = 0.f;
|
|
|
|
ent.timeFade = 15.f;
|
|
|
|
|
|
|
|
entries.push_front(ent);
|
|
|
|
|
|
|
|
firstY -= h;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string ChatWindow::ColoredMessage(const std::string & msg,
|
|
|
|
char c){
|
|
|
|
SPADES_MARK_FUNCTION_DEBUG();
|
|
|
|
std::string s;
|
|
|
|
s += c;
|
|
|
|
s += msg;
|
|
|
|
s += MsgColorRestore;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string ChatWindow::TeamColorMessage(const std::string &msg,
|
|
|
|
int team){
|
|
|
|
SPADES_MARK_FUNCTION_DEBUG();
|
|
|
|
if(team == 0)
|
|
|
|
return ColoredMessage(msg, MsgColorTeam1);
|
|
|
|
if(team == 1)
|
|
|
|
return ColoredMessage(msg, MsgColorTeam2);
|
|
|
|
if(team == 2)
|
|
|
|
return ColoredMessage(msg, MsgColorTeam3);
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Vector4 ConvertColor(IntVector3 v){
|
|
|
|
return MakeVector4((float)v.x / 255.f,
|
|
|
|
(float)v.y / 255.f,
|
|
|
|
(float)v.z / 255.f,
|
|
|
|
1.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 ChatWindow::GetColor(char c){
|
|
|
|
switch(c){
|
|
|
|
case MsgColorTeam1:
|
|
|
|
if(client->GetWorld())
|
|
|
|
return ConvertColor(client->GetWorld()->GetTeam(0).color);
|
|
|
|
case MsgColorTeam2:
|
|
|
|
if(client->GetWorld())
|
|
|
|
return ConvertColor(client->GetWorld()->GetTeam(1).color);
|
|
|
|
case MsgColorTeam3:
|
|
|
|
if(client->GetWorld())
|
|
|
|
return ConvertColor(client->GetWorld()->GetTeam(2).color);
|
|
|
|
case MsgColorRed:
|
|
|
|
return MakeVector4(1,0,0,1);
|
|
|
|
case MsgColorSysInfo:
|
|
|
|
return MakeVector4(0,1,0,1);
|
|
|
|
default:
|
|
|
|
return MakeVector4(1,1,1,1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatWindow::Update(float dt) {
|
|
|
|
|
|
|
|
if(firstY < 0.f){
|
|
|
|
firstY += dt * std::max(100.f, -firstY);
|
|
|
|
if(firstY > 0.f)
|
|
|
|
firstY = 0.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::list<ChatEntry>::iterator it;
|
|
|
|
float height = GetHeight();
|
|
|
|
float y = firstY;
|
|
|
|
|
|
|
|
std::vector<std::list<ChatEntry>::iterator> removedItems;
|
|
|
|
|
|
|
|
for(it = entries.begin(); it != entries.end(); it++){
|
|
|
|
ChatEntry& ent = *it;
|
|
|
|
if(y + ent.height > height){
|
|
|
|
// should fade out
|
|
|
|
ent.fade -= dt * 4.f;
|
|
|
|
if(ent.fade < 0.f){
|
|
|
|
ent.fade = 0.f;
|
|
|
|
removedItems.push_back(it);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}else if(y + ent.height > 0.f){
|
|
|
|
// should fade in
|
|
|
|
ent.fade += dt * 4.f;
|
|
|
|
if(ent.fade > 1.f)
|
|
|
|
ent.fade = 1.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
ent.timeFade -= dt;
|
|
|
|
if(ent.timeFade < 0.f){
|
|
|
|
removedItems.push_back(it);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
y += ent.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(size_t i = 0; i < removedItems.size(); i++)
|
|
|
|
entries.erase(removedItems[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatWindow::Draw() {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
float winX = 4.f;
|
2013-08-26 17:53:14 +09:00
|
|
|
float winY = killfeed ? 8.f :
|
|
|
|
(float)renderer->ScreenHeight() * .5f;
|
2013-08-18 16:18:06 +09:00
|
|
|
std::list<ChatEntry>::iterator it;
|
|
|
|
|
|
|
|
float lHeight = GetLineHeight();
|
|
|
|
|
|
|
|
float y = firstY;
|
|
|
|
|
|
|
|
Vector4 shadowColor = {0, 0, 0, 0.5};
|
|
|
|
|
|
|
|
for(it = entries.begin(); it != entries.end(); it++){
|
|
|
|
ChatEntry& ent = *it;
|
|
|
|
|
|
|
|
std::string msg = ent.msg;
|
|
|
|
Vector4 color = GetColor(MsgColorRestore);
|
|
|
|
float tx = 0.f, ty = y;
|
|
|
|
float fade = ent.fade;
|
|
|
|
if(ent.timeFade < 1.f)
|
|
|
|
fade *= ent.timeFade;
|
|
|
|
shadowColor.w = .5f * fade;
|
|
|
|
color.w *= fade;
|
2013-10-24 01:25:59 +02:00
|
|
|
std::string ch = "a"; //let's not make a new object for each character.
|
2013-08-18 16:18:06 +09:00
|
|
|
for(size_t i = 0; i < msg.size(); i++){
|
|
|
|
if(msg[i] == 13 || msg[i] == 10){
|
|
|
|
tx = 0.f; ty += lHeight;
|
|
|
|
}else if(msg[i] <= MsgColorMax){
|
|
|
|
color = GetColor(msg[i]);
|
|
|
|
color.w *= fade;
|
|
|
|
}else{
|
2013-10-24 01:25:59 +02:00
|
|
|
ch[0] = msg[i];
|
2013-08-18 16:18:06 +09:00
|
|
|
font->Draw(ch,
|
|
|
|
MakeVector2(tx + winX + 1.f,
|
|
|
|
ty + winY + 1.f),
|
|
|
|
1.f, shadowColor);
|
|
|
|
font->Draw(ch,
|
|
|
|
MakeVector2(tx + winX,
|
|
|
|
ty + winY),
|
|
|
|
1.f, color);
|
|
|
|
tx += font->Measure(ch).x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
y += ent.height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|