forked from eu07/maszyna
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNames.cpp
183 lines (166 loc) · 6.26 KB
/
Names.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include <vcl.h>
#pragma hdrstop
#include "Names.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
/*
Moduł zarządzający plikami oraz wyszukiwaniem obiektów wg nazw.
1. Ma przydzielony z góry (EU07.INI) obszar pamięci (rzędu 16MB).
2. W przypadku przepełnienia dostępnej pamięci wystąpi błąd wczytywania.
3. Obszar ten będzie zużywany na rekordy obiektów oraz ciągi tekstowe z nazwami.
4. Rekordy będą sortowane w ramach typu (tekstury, dźwięki, modele, node, eventy).
5. Pierwszy etap wyszukiwania to 5 bitów z pierwszego bajtu i 3 z drugiego (256).
6. Dla plików istnieje możliwość wczytania ich w innym terminie.
7. Możliwość wczytania plików w oddzielnym watku (np. tekstur).
Obsługiwane pliki:
1. Tekstury, można wczytywać później, rekord przechowuje numer podany przez kartę graficzną.
2. Dźwięki, można wczytać później.
3. Modele, można wczytać później o ile nie mają animacji eventami i nie dotyczą pojazdów.
Obiekty sortowane wg nazw, można dodawać i usuwać komórki scenerii:
4. Tory, drogi, rzeki - wyszukiwanie w celu sprawdzenia zajetości.
5. Eventy - wyszukiwane przy zewnętrznym wywołaniu oraz podczas wczytywania.
6. Pojazdy - wyszukiwane w celu wysyłania komend.
7. Egzemplarze modeli animowanych - wyszukiwanie w celu połączenia z animacjami.
*/
void ItemRecord::TreeAdd(ItemRecord *r, int c)
{ // dodanie rekordu do drzewa - ustalenie w której gałęzi
// zapisać w (iFlags) ile znaków jest zgodnych z nadrzędnym, żeby nie sprawdzać wszystkich od
// zera
if ((cName[c] && r->cName[c]) ? cName[c] == r->cName[c] : false)
TreeAdd(r, c + 1); // ustawić wg kolejnego znaku, chyba że zero
else if ((unsigned char)(cName[c]) < (unsigned char)(r->cName[c]))
{ // zero jest najmniejsze - doczepiamy jako (rNext)
if (!rNext)
rNext = r;
else
rNext->TreeAdd(r, 0); // doczepić do tej gałęzi
}
else
{
if (!rPrev)
rPrev = r;
else
rPrev->TreeAdd(r, 0); // doczepić do tej gałęzi
}
};
void ItemRecord::ListGet(ItemRecord *r, int *&n)
{ // rekurencyjne wypełnianie posortowanej listy na podstawie drzewa
if (rPrev)
rPrev->ListGet(r, n); // dodanie wszystkich wcześniejszych
*n++ = this - r; // dodanie swojego indeksu do tabeli
if (rNext)
rNext->ListGet(r, n); // dodanie wszystkich późniejszych
};
void *__fastcall ItemRecord::TreeFind(const char *n)
{ // wyszukanie ciągu (n)
ItemRecord *r = TreeFindRecord(n);
return r ? r->pData : NULL;
};
ItemRecord *__fastcall ItemRecord::TreeFindRecord(const char *n)
{ // wyszukanie ciągu (n)
ItemRecord *r = this; //żeby nie robić rekurencji
int i = 0;
do
{
if (!n[i])
if (!r->cName[i])
return r; // znaleziony
if (n[i] == r->cName[i])
++i; // porównać kolejny znak
else if ((unsigned char)(n[i]) < (unsigned char)(r->cName[i]))
{
i = 0; // porównywać od nowa
r = r->rPrev; // wcześniejsza gałąź drzewa
}
else
{
i = 0; // porównywać od nowa
r = r->rNext; // późniejsza gałąź drzewa
}
} while (r);
return NULL;
};
TNames::TNames()
{ // tworzenie bufora
iSize = 16 * 1024 * 1024; // rozmiar bufora w bajtach
cBuffer = new char[iSize];
ZeroMemory(cBuffer, iSize); // nie trzymać jakiś starych śmieci
rRecords = (ItemRecord *)cBuffer;
cLast = cBuffer + iSize; // bajt za buforem
iLast = -1;
ZeroMemory(rTypes, 20 * sizeof(ItemRecord *));
};
int TNames::Add(int t, const char *n)
{ // dodanie obiektu typu (t) o nazwie (n)
int len = strlen(n) + 1; // ze znacznikiem końca
cLast -= len; // rezerwacja miejsca
memcpy(cLast, n, len); // przekopiowanie tekstu do bufora
// cLast[len-1]='\0';
rRecords[++iLast].cName = cLast; // połączenie nazwy z rekordem
rRecords[iLast].iFlags = t;
if (!rTypes[t])
rTypes[t] = rRecords + iLast; // korzeń drzewa, bo nie było wcześniej
else
rTypes[t]->TreeAdd(rRecords + iLast, 0); // doczepienie jako gałąź
// rTypes[t]=Sort(t); //sortowanie uruchamiać ręcznie
if ((iLast & 0x3F) == 0) // nie za często, bo sortowania zajmą więcej czasu niż wyszukiwania
Sort(t); // optymalizacja drzewa co jakiś czas
return iLast;
}
int TNames::Add(int t, const char *n, void *d)
{
int i = Add(t, n);
rRecords[iLast].pData = d;
return i;
};
bool TNames::Update(int t, const char *n, void *d)
{ // dodanie jeśli nie ma, wymiana (d), gdy jest
ItemRecord *r = FindRecord(t, n); // najpierw sprawdzić, czy już jest
if (r)
{ // przy zdublowaniu nazwy podmieniać w drzewku na późniejszy
r->pData = d;
return true; // duplikat
}
// Add(t,n,d); //nazwa unikalna
return false; // został dodany nowy
};
ItemRecord *__fastcall TNames::TreeSet(int *n, int d, int u)
{ // rekurencyjne wypełnianie drzewa pozycjami od (d) do (u)
if (d == u)
{
rRecords[n[d]].rPrev = rRecords[n[d]].rNext = NULL;
return rRecords + n[d]; // tej gałęzi nie ma
}
else if (d > u)
return NULL;
int p = (u + d) >> 1; // połowa
rRecords[n[p]].rPrev = TreeSet(n, d, p - 1); // zapisanie wcześniejszych gałęzi
rRecords[n[p]].rNext = TreeSet(n, p + 1, u); // zapisanie późniejszych gałęzi
return rRecords + n[p];
};
void TNames::Sort(int t)
{ // przebudowa drzewa typu (t), zwraca wierzchołek drzewa
if (iLast < 3)
return; // jak jest mało, to nie ma sensu sortować
if (rTypes[t]) // jeśli jest jakiś rekord danego typu
{
int *r = new int[iLast + 1]; // robocza tablica indeksów - numery posortowanych rekordów
int *q = r; // wskaźnik roboczy, przekazywany przez referencję
rTypes[t]->ListGet(rRecords, q); // drzewo jest już posortowane - zamienić je na listę
rTypes[t] = TreeSet(r, 0, (q - r) - 1);
delete[] r;
}
return;
};
ItemRecord *__fastcall TNames::FindRecord(const int t, const char *n)
{ // poszukiwanie rekordu w celu np. zmiany wskaźnika
return rTypes[t] ? rTypes[t]->TreeFindRecord(n) : NULL;
};