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