1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include "countryflags.h"
4
5#include <base/io.h>
6#include <base/log.h>
7#include <base/math.h>
8#include <base/str.h>
9
10#include <engine/graphics.h>
11#include <engine/shared/config.h>
12#include <engine/shared/linereader.h>
13#include <engine/storage.h>
14
15void CCountryFlags::LoadCountryflagsIndexfile()
16{
17 const char *pFilename = "countryflags/index.txt";
18 CLineReader LineReader;
19 if(!LineReader.OpenFile(File: Storage()->OpenFile(pFilename, Flags: IOFLAG_READ, Type: IStorage::TYPE_ALL)))
20 {
21 log_error("countryflags", "couldn't open index file '%s'", pFilename);
22 return;
23 }
24
25 char aOrigin[128];
26 while(const char *pLine = LineReader.Get())
27 {
28 if(!str_length(str: pLine) || pLine[0] == '#') // skip empty lines and comments
29 continue;
30
31 str_copy(dst&: aOrigin, src: pLine);
32 const char *pReplacement = LineReader.Get();
33 if(!pReplacement)
34 {
35 log_error("countryflags", "unexpected end of index file");
36 break;
37 }
38
39 if(pReplacement[0] != '=' || pReplacement[1] != '=' || pReplacement[2] != ' ')
40 {
41 log_error("countryflags", "malformed replacement for index '%s'", aOrigin);
42 continue;
43 }
44
45 int CountryCode = str_toint(str: pReplacement + 3);
46 if(CountryCode < CODE_LB || CountryCode > CODE_UB)
47 {
48 log_error("countryflags", "country code '%i' not within valid code range [%i..%i]", CountryCode, CODE_LB, CODE_UB);
49 continue;
50 }
51
52 // load the graphic file
53 char aBuf[128];
54 CImageInfo Info;
55 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "countryflags/%s.png", aOrigin);
56 if(!Graphics()->LoadPng(Image&: Info, pFilename: aBuf, StorageType: IStorage::TYPE_ALL))
57 {
58 log_error("countryflags", "failed to load '%s'", aBuf);
59 continue;
60 }
61
62 // add entry
63 CCountryFlag CountryFlag;
64 CountryFlag.m_CountryCode = CountryCode;
65 str_copy(dst&: CountryFlag.m_aCountryCodeString, src: aOrigin);
66 CountryFlag.m_Texture = Graphics()->LoadTextureRawMove(Image&: Info, Flags: 0, pTexName: aBuf);
67
68 if(g_Config.m_Debug)
69 {
70 log_debug("countryflags", "loaded country flag '%s'", aOrigin);
71 }
72 m_vCountryFlags.push_back(x: CountryFlag);
73 }
74
75 std::sort(first: m_vCountryFlags.begin(), last: m_vCountryFlags.end());
76
77 // find index of default item
78 size_t DefaultIndex = 0;
79 for(size_t Index = 0; Index < m_vCountryFlags.size(); ++Index)
80 if(m_vCountryFlags[Index].m_CountryCode == -1)
81 {
82 DefaultIndex = Index;
83 break;
84 }
85
86 // init LUT
87 std::fill(first: std::begin(arr&: m_aCodeIndexLUT), last: std::end(arr&: m_aCodeIndexLUT), value: DefaultIndex);
88 for(size_t i = 0; i < m_vCountryFlags.size(); ++i)
89 m_aCodeIndexLUT[maximum(a: 0, b: (m_vCountryFlags[i].m_CountryCode - CODE_LB) % CODE_RANGE)] = i;
90}
91
92void CCountryFlags::OnInit()
93{
94 // load country flags
95 m_vCountryFlags.clear();
96 LoadCountryflagsIndexfile();
97 if(m_vCountryFlags.empty())
98 {
99 log_error("countryflags", "failed to load country flags. folder='countryflags/'");
100 CCountryFlag DummyEntry;
101 DummyEntry.m_CountryCode = -1;
102 DummyEntry.m_aCountryCodeString[0] = '\0';
103 m_vCountryFlags.push_back(x: DummyEntry);
104 }
105
106 m_FlagsQuadContainerIndex = Graphics()->CreateQuadContainer(AutomaticUpload: false);
107 Graphics()->SetColor(r: 1.0f, g: 1.0f, b: 1.0f, a: 1.0f);
108 Graphics()->QuadsSetSubset(TopLeftU: 0.0f, TopLeftV: 0.0f, BottomRightU: 1.0f, BottomRightV: 1.0f);
109 Graphics()->QuadContainerAddSprite(QuadContainerIndex: m_FlagsQuadContainerIndex, X: 0.0f, Y: 0.0f, Width: 1.0f, Height: 1.0f);
110 Graphics()->QuadContainerUpload(ContainerIndex: m_FlagsQuadContainerIndex);
111}
112
113size_t CCountryFlags::Num() const
114{
115 return m_vCountryFlags.size();
116}
117
118const CCountryFlags::CCountryFlag &CCountryFlags::GetByCountryCode(int CountryCode) const
119{
120 return GetByIndex(Index: m_aCodeIndexLUT[maximum(a: 0, b: (CountryCode - CODE_LB) % CODE_RANGE)]);
121}
122
123const CCountryFlags::CCountryFlag &CCountryFlags::GetByIndex(size_t Index) const
124{
125 return m_vCountryFlags[Index % m_vCountryFlags.size()];
126}
127
128void CCountryFlags::Render(const CCountryFlag &Flag, ColorRGBA Color, float x, float y, float w, float h)
129{
130 if(Flag.m_Texture.IsValid())
131 {
132 Graphics()->TextureSet(Texture: Flag.m_Texture);
133 Graphics()->SetColor(Color);
134 Graphics()->QuadsSetRotation(Angle: 0.0f);
135 Graphics()->RenderQuadContainerEx(ContainerIndex: m_FlagsQuadContainerIndex, QuadOffset: 0, QuadDrawNum: -1, X: x, Y: y, ScaleX: w, ScaleY: h);
136 }
137}
138
139void CCountryFlags::Render(int CountryCode, ColorRGBA Color, float x, float y, float w, float h)
140{
141 Render(Flag: GetByCountryCode(CountryCode), Color, x, y, w, h);
142}
143