Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,852
Записей в блоге: 2

Разбор строки

05.12.2025, 16:05. Показов 5739. Ответов 45
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день

Нужно разобрать (распарсить) такую строку
f 4904/74/6472 4842/76/6473 4848/75/6474
Это из популярного .obj файла, "f" - описание одного полигона (фейса). Каждая тройка чисел - индексы для позиции, UV и нормали вертекса соответственно. Число троек любое, фейс может ссылаться на любое число вертексов. Позиция есть всегда, UV и/или нормали могут отсутствовать, примеры
f 4904 4842 4848 ; только позиция
f 4904/74 4842/76 4848/75 ; позиция + UV
f 4904//6472 4842//6473 4848//6474 ; позиция + нормаль
Для простоты считаем что на выходе должны получить такую структуру
C++
1
2
3
struct Face {
 std::vector<int> m_pos, m_uv, m_normal;
};
Есть лучшие предложения по организации данных - с удовольствием послушаю.
Требования к разбору: юникод здесь не актуален (считаем что только латинский текст). Никакого копирования данных строки. Наверно бум юзать std::string_view, мы ведь его так любим (во всяком случае хвалим). Возможно первое что приходит в голову - использовать std::istringstream. Но ведь (я слышал) он deprecated? И как подружить его с std::string_view?

Спасибо
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
05.12.2025, 16:05
Ответы с готовыми решениями:

Разбор аргументов командной строки
Для Unix существуют специальные средства для разбора опций командной строки (функции GNU getopt и...

Разбор строки
Доброго времени суток. Прошу Вашей помощи в этом казалось бы не сложном деле. Не так давно пишу на...

Разбор строки из консоли и вопрос по g++
Всем доброго времени суток :) Недавно начал изучать C++ Вот есть пару вопросов... Первое -...

45
Just Do It!
 Аватар для XLAT
4202 / 2660 / 654
Регистрация: 23.09.2014
Сообщений: 9,019
Записей в блоге: 3
07.12.2025, 16:11
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от alecss131 Посмотреть сообщение
Что за бред? Бинарь тоже спокойно экспортируется,
люблю таких уверенных, аш кушать не могу)))

ваш мир, это мир нвида и амд аппартки - вот в котором, мда, вы спокойно себя чувствуете.

а теперь вопрос:
в какой заднице была ваша нвидиа и амд в 1980 году,
когда компания друзей из Wavefront Technologies разрабатывала формат моделей OBJ ???

второй вопрос:
что вы знаете о том зоопарке в аппаратной части в те времена?

мда,
то что люди не умеют абстрагироваться как раз и делает их такими самоуверенными спокойными сишкошкодерами))

Добавлено через 18 минут
1.
Цитата Сообщение от Igor3D Посмотреть сообщение
нездоровая затея
Цитата Сообщение от Igor3D Посмотреть сообщение
Лучше
Цитата Сообщение от Igor3D Посмотреть сообщение
нехорошо
Цитата Сообщение от Igor3D Посмотреть сообщение
не стоит
Цитата Сообщение от Igor3D Посмотреть сообщение
напрасный трюк
у меня нет уверенности, что такая уверенная аргументация мне будет полезна.

2.
Цитата Сообщение от Igor3D Посмотреть сообщение
то почему бы не использовать sscanf
потому что тру это когда мы абстрагируемся от источника.

3.
Цитата Сообщение от Igor3D Посмотреть сообщение
std::string_view
да, есть моменты где можно переделать на string_view,
если вы сделаете стенд,
я могу сделать вам на string_view,

я отдаю предпочтение скорости написанию кода и его изяществу вместо скорости его работы.

4.
Цитата Сообщение от Igor3D Посмотреть сообщение
да еще и в deprecated stringstream.
первый раз слышу.
проверьте у себя эту инфу.

5.
Цитата Сообщение от Igor3D Посмотреть сообщение
Заметим что во всех случаях есть какая-то "ударная" ф-ция которая делает что нужно, и код группируется возле нее.
))
я вас обожаю.

6.
вот дельное замечание:
Цитата Сообщение от Igor3D Посмотреть сообщение
int (вместо float), это индексы.
уверенность тут не нужна, чтобы глянуть в вики, но в вики окзалось гуано,
поэтому я нашел нормальный пример с моделью obj...

куб великоват - взял попроще - квадрат:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# A 2 x 2 square mapped with a 1 x 1 square
# texture stretched to fit the square exactly.
mtllib master.mtl
 
v 0.100000 2.200000 0.300000
v 0.100000 0.200000 0.300000
v 2.100000 0.200000 0.300000
v 2.100000 2.200000 0.300000
vt 0.040000 1.000000
vt 0.040000 0.040000
vt 1.000000 0.040000
vt 1.000000 1.000000
 
# 4 vertices
usemtl wood
# The first number is the point and the second is the texture point
f 1/1 2/2 3/3 4/4
# 1 element
поправил свой ДЕМО-код выше:
C++
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/// DEMO::Obj-Loader::version::0.3
///----------------------------------------------------------------------------|
/// C++20
/// source code: UTF-8
/// https://github.com/garykac/3d-cubes/blob/master/cube.obj
///----------------------------------------------------------------------------|
#include <iostream>
#include <sstream>
#include <vector>
#include <format>
 
#define l(a) std::cout << #a << " = " << (a) << '\n';
 
template <typename... TT> void Banner(TT&&... vals)
{   ((std::cout << vals << std::endl), ...);
}
 
 
///----------------------------------------------------------------------------|
/// Генератор входных данных.
///-------------------------------------------------------------------- GenTest:
struct GenTest
{   static std::string get(int n = 1)
    {   constexpr const char* ss
        {   R"(
# A 2 x 2 square mapped with a 1 x 1 square
# texture stretched to fit the square exactly.
mtllib master.mtl
 
v 0.100000 2.200000 0.300000
v 0.100000 0.200000 0.300000
v 2.100000 0.200000 0.300000
v 2.100000 2.200000 0.300000
vt 0.040000 1.000000
vt 0.040000 0.040000
vt 1.000000 0.040000
vt 1.000000 1.000000
 
# 4 vertices
usemtl wood
# The first number is the point and the second is the texture point
f 1/1 2/2 3/3 4/4
# 1 element
            )"
        };
 
        std::string s;
        while (n--) s += ss;
        return      s;
    }
};
 
 
///----------------------------------------------------------------------------|
/// Грань.
///----------------------------------------------------------------------- Face:
struct Face : std::array<std::vector<int>, 3>
{   enum EFACE
    {   POS,
        UV ,
        NORM
    };
};
 
struct Vertex : std::array<std::vector<float>, 3>
{   enum EVERTEX
    {   POS,
        UV ,
        NORM
    };
};
 
using cvf_t = const std::vector<float>;
void  out(std::ostream& o, cvf_t& m, std::string_view s, const size_t step)
{
    if(m.empty()) return;
    for(    size_t i = 0; i < m.size();)
    {   o << s;
        for(size_t j = 0; j < step && i < m.size(); ++j, ++i)
        {   o << std::format("{:6}", m[i]);
        }   o << '\n';
    }       o << '\n';
}
 
std::ostream& operator<<(std::ostream& o, const Vertex& f)
{   out(o, f[Vertex::POS ], "v  ---> ", 3);
    out(o, f[Vertex::UV  ], "vt ---> ", 2);
    out(o, f[Vertex::NORM], "vn ---> ", 3);
    return o;
}
 
std::ostream& operator<<(std::ostream& o, const Face& f)
{   o << "f-v : "; for(const auto n : f[Face::POS ]) {o << n << ' ';} o << '\n';
    o << "f-vt: "; for(const auto n : f[Face::UV  ]) {o << n << ' ';} o << '\n';
    o << "f-vn: "; for(const auto n : f[Face::NORM]) {o << n << ' ';} o << '\n';
    return o;
}
 
 
struct ObjLoader;
std::ostream& operator<<(std::ostream& o, const ObjLoader& m);
 
///----------------------------------------------------------------------------|
/// ObjLoader
///------------------------------------------------------------------ ObjLoader:
struct  ObjLoader : Face, Vertex
{       ObjLoader()
        {
        }
 
    ///------------------------------|
    /// Получить данные о Vertex.    |
    ///------------------------------:
    const std::vector<float>& getVertex(Vertex::EVERTEX i) const
    {   return (*static_cast<const Vertex*>(this))[size_t(i)];
    }
 
    ///------------------------------|
    /// Получить данные об индексах. |
    ///------------------------------:
    const std::vector<int>& getFace(Face::EFACE i) const
    {   return (*static_cast<const Face*>(this))[size_t(i)];
    }
 
    void go(std::istream&& is)
    {   size_t cnt{};
 
        Face  & F = *this;
        Vertex& V = *this;
 
        for(std::string s; std::getline(is, s); ++cnt)
        {
            if(s[0] != 'f')
            {
                const std::string_view a{s.substr(0, 2)};
 
                     if(a == "v ") go3d(s, V[Vertex::POS ]);
                else if(a == "vn") go3d(s, V[Vertex::NORM]);
                else if(a == "vt") go3d(s, V[Vertex::UV  ]);
                continue;
            }
 
            for(std::stringstream is(s); is >> s;)
            {   if(s[0] == 'f') continue;
                if(s[0] == ';') break;
 
                size_t i{};
                size_t d  ;
 
                if(!std::isdigit(s.back())) throw(cnt);
 
                for(std::stringstream is(s); std::getline(is, s, '/'); ++i)
                {   if(i > 2)              throw(cnt);
                    if(s.empty()&& i == 1) continue  ;
 
                    try
                    {   F[i].push_back(std::stoi(s, &d));
                        if(d != s.size())     throw(cnt);
                    }
                    catch(...)
                    {   throw(cnt);
                    }
                }
            }
        }
    }
 
    void go3d(std::string_view ss, std::vector<float>& res)
    {   size_t cnt{};
 
        std::string s;
 
        for(std::stringstream is(ss.data()); is >> s; ++cnt)
        {   if(0 == cnt) continue;
            size_t  d;
 
            try
            {   res.push_back(std::stod(s, &d));
                if(d != s.size())           throw(cnt);
            }
            catch(...)
            {   throw(cnt);
            }
        }
    }
 
    static void test()
    {   try
        {   ObjLoader    objLoader;
            objLoader.go(std::stringstream(GenTest::get()));
            std::cout << objLoader << '\n';
        }
        catch(size_t cnt)
        {   std::cout << std::format("ERROR: ObjLoader line={}...\n\n", cnt);
            return;
        }
 
        Banner(
            "///--------------------------|",
            "/// Тестирование УСПЕШНО!    |",
            "///--------------------------|\n");
    }
 
private:
};
 
std::ostream& operator<<(std::ostream& o, const ObjLoader& m)
{          o << (Vertex)(m);
           o << (Face  )(m);
    return o;
}
 
 
///----------------------------------------------------------------------------|
/// main
///----------------------------------------------------------------------- main:
int main()
{
    std::system        (  "chcp 65001>0");
    std::locale::global(std::locale("C"));
 
    Banner(
        "///--------------------------------|",
        "/// Привет, я есть OBJ-LOADER!     |",
        "///--------------------------------|\n");
 
    ObjLoader::test();
 
    std::cout << "ПРОГРАММА ЗАВЕРШИЛА РАБОТУ." << std::endl;
}
выхлоп:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
///--------------------------------|
/// Привет, я есть OBJ-LOADER!     |
///--------------------------------|
 
v  --->    0.1   2.2   0.3
v  --->    0.1   0.2   0.3
v  --->    2.1   0.2   0.3
v  --->    2.1   2.2   0.3
 
vt --->   0.04     1
vt --->   0.04  0.04
vt --->      1  0.04
vt --->      1     1
 
f-v : 1 2 3 4
f-vt: 1 2 3 4
f-vn:
 
///--------------------------|
/// Тестирование УСПЕШНО!    |
///--------------------------|
 
ПРОГРАММА ЗАВЕРШИЛА РАБОТУ.
7.
Цитата Сообщение от Royal_X Посмотреть сообщение
Почему они довольны?
предлагаю план надежный, как швейцарские часы:

1. заколбасить тетрис с физикой.
2. оборудовать виртуальную онлайн студию.
3. Наталью наймем сеньором, а Игоря мидлом.
4. обязательно в наличии лопата, которой мы с тобой посменно будем грести бабло.
0
 Аватар для Наталья8
522 / 372 / 66
Регистрация: 09.03.2016
Сообщений: 3,943
07.12.2025, 16:23
Начальник...
0
Just Do It!
 Аватар для XLAT
4202 / 2660 / 654
Регистрация: 23.09.2014
Сообщений: 9,019
Записей в блоге: 3
07.12.2025, 16:27
Цитата Сообщение от Наталья8 Посмотреть сообщение
Начальник...
начальником будет Royal_X
я буду специалистом по командировкам на Бали...
0
 Аватар для Наталья8
522 / 372 / 66
Регистрация: 09.03.2016
Сообщений: 3,943
07.12.2025, 16:33
(tetris) two pieces.rar
Где сядешь там и слезешь,
раньше сядешь раньше выйдешь.
0
Just Do It!
 Аватар для XLAT
4202 / 2660 / 654
Регистрация: 23.09.2014
Сообщений: 9,019
Записей в блоге: 3
07.12.2025, 16:40
Цитата Сообщение от Наталья8 Посмотреть сообщение
(tetris) two pieces.rar
нет.
нужно типа такого, но в 3d
0
 Аватар для Наталья8
522 / 372 / 66
Регистрация: 09.03.2016
Сообщений: 3,943
07.12.2025, 16:43
Тише едешь, шире морда.
Не пишу такого. Народ не поймёт...
Всё равно обсерут...
Есть ещё пословица, но лучше... промолчу...
0
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,852
Записей в блоге: 2
07.12.2025, 18:39  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
нужно разобраться, на что делается упор - воздушность кода или эффективность?
Я ж задавал вопрос - как часто и в каком количестве это всё разбирается ?
Если единожды перед запуском игры - то берём строковый поток, ждём 5 секунд и всё в шоколаде.
А что это за философия такая? Почему надо обязательно выбирать, чем-то жертвовать и.т.п.? Так бывает, но далеко не всегда. Напр здесь можно "быть богатым и здоровым"
Цитата Сообщение от Алексей1153 Посмотреть сообщение
Если нужна молотилка - это как у меня. Изменение формата не предусматривается.
Да уж, после Вашей молотилки костей не соберешь Изменение формата... лучше исходить из того что доделывать приходится всегда, мы/заказчик просто не знаем что может всплыть, ну хотя бы
f 1751/2732/3260 1752/2734/3260 1782/2794/3305 1781/2793/3305\
1752/2738/3262 1753/2737/3262 1783/2795/3306 1782/2796/3306
Т.е. если вертексов много, то строки склеиваются (обратный слеш в конце), здесь у фейса 8 вертексов. Я не меняю задачу стартового поста, это я к тому что простота и понятность кода ("читабельность") - вещь важнейшая. Если оно даже работает, но код мозголомный - нет смысла его менять, проще написать заново.
Цитата Сообщение от XLAT Посмотреть сообщение
C++
1
2
3
4
5
6
7
8
9
10
11
for(std::stringstream is(s); std::getline(is, s, '/'); ++i)
                {   if(i > 2)              throw(cnt);
                    if(s.empty()&& i == 1) continue  ;
try
                    {   F[i].push_back(std::stoi(s, &d));
                        if(d != s.size())     throw(cnt);
                    }
                    catch(...)
                    {   throw(cnt);
                    }
                }
Неэлегантно, вымучено. Хотя вполне возможно что все правильно. Три if'a и в каждый надо вникать, (хорошо) зная при этом специфику формата. Помощи от имен (ф-ций, переменных) никакой. Ну а с ошибками - "абы було"

Хорошо, как бы я делал (а то критиковать все мастера). Светлая сторона getline что мы откусываем от строки "слово за словом", решая проблемы "по мере поступления". Думаю так лучше чем сплитить все. Никто не мешает сделать то же самое для std::string_view, псевдокод
C++
1
2
3
4
auto word = NextWord(str);
if (word.empty()) continue;
if (word == 'f')
 ParseFace(facets, str);
Здесь "слово" - любая последовательность символов не содержащая пробелов/спейсов. Следующий шажок
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void ParseFace( std::vector<Face> & facets, std::string_view str )
{
 int done = 0;
 while (true) {
  auto word = NextWord(str);
  if (word.empty()) break;
  ++done;
  Face face;
  ParseIndices(face, word);
  facets.push_back(face);
 }
 if (!done)
  return Error(err_missed_face);
}
Ну и так далее, здесь писать - одно удовольствие
0
Just Do It!
 Аватар для XLAT
4202 / 2660 / 654
Регистрация: 23.09.2014
Сообщений: 9,019
Записей в блоге: 3
07.12.2025, 19:19
Цитата Сообщение от Igor3D Посмотреть сообщение
здесь писать - одно удовольствие
ок,
я уже 4 версию написал, а где же ваш код то, от которого вы получаете удовольствие?

C++
1
/// DEMO::Obj-Loader::version-0.4
в тесте используется реальный файл модели obj
скачать можно отсюда...

C++
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/// DEMO::Obj-Loader::version-0.4
///----------------------------------------------------------------------------|
/// C++20
/// source code: UTF-8
/// Файл "cube.obj": https://github.com/garykac/3d-cubes/blob/master/cube.obj
///----------------------------------------------------------------------------|
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <format>
 
#define l(a) std::cout << #a << " = " << (a) << '\n';
 
template <typename... TT> void Banner(TT&&... vals)
{   ((std::cout << vals << std::endl), ...);
}
 
 
///----------------------------------------------------------------------------|
/// Генератор входных данных.
///-------------------------------------------------------------------- GenTest:
struct GenTest
{   static std::string get(int n = 1)
    {   constexpr const char* ss
        {
            /*01*/ "# A 2 x 2 square mapped with a 1 x 1 square\n"
            /*02*/ "# texture stretched to fit the square exactly.\n"
            /*03*/ "mtllib master.mtl\n"
            /*04*/ "#---------------------------\n"
            /*05*/ "v 0.100000 2.200000 0.300000\n"
            /*06*/ "v 0.100000 0.200000 0.300000\n"
            /*07*/ "v 2.100000 0.200000 0.300000\n"
            /*08*/ "v 2.100000 2.200000 0.300000\n"
            /*09*/ "vt 0.04    0.040000\n"
            /*10*/ "vt 1.00    0.040000\n"
            /*11*/ "vt 1.00    1.000000\n"
            /*12*/ "vt 0.04 \t 1.000000\n"
            /*13*/ "#---------------------------\n"
            /*14*/ "# 4 vertices\n"
            /*15*/ "usemtl wood\n"
            /*16*/ "# The first number is point and second is the texture point\n"
            /*17*/ "f 1/1 2/2 3/3 4/4\n"
            /*18*/ "# 1 element\n"
        };
 
        std::string s;
        while (n--) s += ss;
        return      s;
    }
};
 
 
///----------------------------------------------------------------------------|
/// Вертексы и индексы.
///---------------------------------------------------------------------- BaseV:
template<typename T>
struct BaseV : std::array<std::vector<T>, 3>
{   enum EFACE
    {    POS,
         UV ,
         NORM
    };
};
 
struct Face   : BaseV<int  > { };
struct Vertex : BaseV<float> { };
 
 
using cvf_t = const std::vector<float>;
void  out(std::ostream& o, cvf_t& m, std::string_view s, const size_t step)
{
    if (m.empty()) return;
    for(    size_t i = 0; i < m.size();)
    {   o << s;
        for(size_t j = 0; j < step && i < m.size(); ++j, ++i)
        {   o << std::format("{:6}", m[i]);
        }   o << '\n';
    }       o << '\n';
}
 
std::ostream& operator<<(std::ostream& o, const Vertex& v)
{   out(o, v[Vertex::POS ], "v  ---> ", 3);
    out(o, v[Vertex::UV  ], "vt ---> ", 2);
    out(o, v[Vertex::NORM], "vn ---> ", 3);
    return o;
}
 
std::ostream& operator<<(std::ostream& o, const Face& f)
{   o << "f-v : "; for(const auto n : f[Face::POS ]) {o << n << ' ';} o << '\n';
    o << "f-vt: "; for(const auto n : f[Face::UV  ]) {o << n << ' ';} o << '\n';
    o << "f-vn: "; for(const auto n : f[Face::NORM]) {o << n << ' ';} o << '\n';
    return o;
}
 
 
///----------------------------------------------------------------------------|
/// ObjLoader
///------------------------------------------------------------------ ObjLoader:
struct  ObjLoader ; std::ostream& operator<<(std::ostream&, const ObjLoader&);
struct  ObjLoader : Face, Vertex
{       ObjLoader()
        {
        }
 
    std::string name;
 
    ///------------------------------|
    /// Получить данные о Vertex.    |
    ///------------------------------:
    const std::vector<float>& getVertex(Face::BaseV::EFACE i) const
    {   return (*static_cast<const Vertex*>(this))[size_t(i)];
    }
 
    ///------------------------------|
    /// Получить данные об индексах. |
    ///------------------------------:
    const std::vector<int>& getFace(Vertex::BaseV::EFACE i) const
    {   return (*static_cast<const Face*>(this))[size_t(i)];
    }
 
    void go(std::istream& is)
    {   cnt = 0;
 
        Face  & F = *this;
        Vertex& V = *this;
 
        std::getline(is, name);
 
        for(std::string s; std::getline(is, s); ++cnt)
        {
            if(s[0] != 'f')
            {
                const std::string_view a{s.substr(0, 2)};
 
                     if(a == "v ") go3d(s, V[Vertex::POS ]);
                else if(a == "vn") go3d(s, V[Vertex::NORM]);
                else if(a == "vt") go3d(s, V[Vertex::UV  ]);
                continue;
            }
 
            for(std::stringstream is(s); is >> s;)
            {   if(s[0] == 'f') continue;
                if(s[0] == '#') break;
 
                size_t i{};
                size_t d  ;
 
                if(!std::isdigit(s.back())) throw(cnt);
 
                for(std::stringstream is(s); std::getline(is, s, '/'); ++i)
                {
                    if(i > 2)              throw(cnt);
                    if(s.empty()&& i == 1) continue  ;
 
                    try
                    {   F[i].push_back(std::stoi(s, &d));
                        if(d != s.size())     throw(cnt);
                    }
                    catch(...)
                    {   throw(cnt);
                    }
                }
            }
        }
    }
 
    void go3d(std::string_view ss, std::vector<float>& res)
    {
        std::string s; std::stringstream is(ss.data()); is >> s;
 
        while(is >> s && s[0] != '#')
        {
            try
            {   size_t  d;
                res.push_back(std::stod(s, &d));
                if(d != s.size())    throw(cnt);
            }
            catch(...)
            {   throw(cnt);
            }
        }
    }
 
    static void test(std::istream&& is = std::stringstream(GenTest::get()))
    {
        if(!is.good())
        {   std::cout << "ERROR: В потоке ничего нет ...\n\n"; return;
        }
 
        try
        {   ObjLoader    objLoader;
            objLoader.go(is);
            std::cout << objLoader << '\n';
        }
        catch(size_t cnt)
        {   std::cout << std::format("ERROR: ObjLoader line={}...\n\n", ++cnt);
            return;
        }
 
        Banner(
            "///--------------------------|",
            "/// Тестирование УСПЕШНО!    |",
            "///--------------------------|\n");
    }
 
private:
    size_t cnt;
};
 
std::ostream& operator<<(std::ostream& o, const ObjLoader& obj)
{          o << std::format("{}\n\n", obj.name);
           o << (Vertex)(obj);
           o << (Face  )(obj);
    return o;
}
 
 
///----------------------------------------------------------------------------|
/// main
///----------------------------------------------------------------------- main:
int main()
{
    std::system        (  "chcp 65001>0");
    std::locale::global(std::locale("C"));
 
    Banner(
        "///--------------------------------|",
        "/// Привет, я есть OBJ-LOADER!     |",
        "///--------------------------------|\n");
 
    ObjLoader::test(std::ifstream("cube.obj"));
 
    std::cout << "ПРОГРАММА ЗАВЕРШИЛА РАБОТУ." << std::endl;
    std::cin.get();
}
выхлоп теста:
Code
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
///--------------------------------|
/// Привет, я есть OBJ-LOADER!     |
///--------------------------------|
 
# cube.obj
 
v  --->      0     0     0
v  --->      0     1     0
v  --->      1     1     0
v  --->      1     0     0
v  --->      0     0     1
v  --->      0     1     1
v  --->      1     1     1
v  --->      1     0     1
 
vn --->      1     0     0
vn --->     -1     0     0
vn --->      0     1     0
vn --->      0    -1     0
vn --->      0     0     1
vn --->      0     0    -1
 
f-v : 3 7 8 3 8 4 1 5 6 1 6 2 7 3 2 7 2 6 4 8 5 4 5 1 8 7 6 8 6 5 3 4 1 3 1 2
f-vt:
f-vn: 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5 6 6 6 6 6 6
 
///--------------------------|
/// Тестирование УСПЕШНО!    |
///--------------------------|
 
ПРОГРАММА ЗАВЕРШИЛА РАБОТУ.
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
07.12.2025, 20:06
Цитата Сообщение от Igor3D Посмотреть сообщение
Почему надо обязательно выбирать, чем-то жертвовать и.т.п.?
такова жизнь. Этот выбор встаёт в реальных проектах очень часто
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2872 / 1042
Регистрация: 01.06.2021
Сообщений: 10,512
07.12.2025, 20:15
Цитата Сообщение от Алексей1153 Посмотреть сообщение
Этот выбор встаёт в реальных проектах очень часто
главное, не делать как в Half Life 2, где ходишь себе спокойно и бац Loading на несколько секунд. Однозначно, это протуп разрабов. Можно было правильно распределить нагрузку на железо, чтобы ПК не фризил во время загрузки...
Если делать с умом, то игрок не почувствует загрузку. Например, у меня в https://royalxxx.itch.io/maze-3d изначально загрузка шла очень долго (поскольку процедурно создается трехмерный лабиринт) и игра фризила, но я потом оптимизировал и добился норм результата.
0
Just Do It!
 Аватар для XLAT
4202 / 2660 / 654
Регистрация: 23.09.2014
Сообщений: 9,019
Записей в блоге: 3
07.12.2025, 20:16
Цитата Сообщение от Алексей1153 Посмотреть сообщение
проектах очень часто
Code
1
"Если выбор у вас не встаёт, то это значит, что ваш выбор берётся по дефолту."(Э.Айнштайн)
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
07.12.2025, 20:18
XLAT, прототипы можно делать без всякого выбора - тяп ляп, лишь бы контрацепцию проверить
1
Just Do It!
 Аватар для XLAT
4202 / 2660 / 654
Регистрация: 23.09.2014
Сообщений: 9,019
Записей в блоге: 3
07.12.2025, 20:19
Цитата Сообщение от Royal_X Посмотреть сообщение
Half Life 2, где ходишь себе спокойно и бац Loading на несколько секунд
если у них там в ресурсах модели в строках, то разрабы - дураки или студенты, или мимо проходили.
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
07.12.2025, 20:20
Цитата Сообщение от Royal_X Посмотреть сообщение
не делать как в Half Life 2, где ходишь себе спокойно и бац Loading на несколько секунд.
не довелось в него играть (вообще последние лет 10 не играл в игры, пичальпичаль)

А он там на каком языке? Может, это они гарбаджколлектор так ловко замаскировали
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2872 / 1042
Регистрация: 01.06.2021
Сообщений: 10,512
07.12.2025, 20:23
Цитата Сообщение от Алексей1153 Посмотреть сообщение
не довелось в него играть
а жаль, скока игр я не играл, все равно больше так не кайфовал, как от Half Life 2 (сама игра и еще два эпизода). Сейчас еще есть Black Mesa - ремейк первой части. Советую с него начинать.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
А он там на каком языке?
у них движок Source, используется вроде С++
0
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,852
Записей в блоге: 2
08.12.2025, 13:02  [ТС]
Цитата Сообщение от XLAT Посмотреть сообщение
я уже 4 версию написал,
Спасибо что потратили свое время, но здесь у меня нет планов получить какой-то рабочий код, о чем уже упоминал
Цитата Сообщение от Igor3D Посмотреть сообщение
Ну (шкурной) задачи "где взять готовый ридер" не ставилось, хотелось пошлифовать логику разбора, лучше это делать на простом и (многим) знакомом примере
Если я правильно понял, Вы предложили
Используя std::getline() находим подстроки до нужного символа
Конечно подтвердить это кодом еще лучше, но смысл и так понятен. Конечно это будет работать, но мне такое решение не нравится. Неужели getline такая уж большая ценность что ради нее мы отказываемся от std::string_view? Понимаю что скорость getline будет хуже но совсем не провальной, устроит. Но как же "поступиться принципами"? Взяв std::string_view мы тем самым заявляем что никаких копий делать не будем, а с getline.. Да, и так ли уж хорош/гениален ф-ционал "искать до заданного символа/подстроки", неужели придумать лучшее совершенно невозможно? Может нам просто не хватает (творческого) размаха?
Цитата Сообщение от XLAT Посмотреть сообщение
я отдаю предпочтение скорости написанию кода и его изяществу
Простите великодушно, но изящество в данном Вашем коде отсутствует. Прямолинейная подгонка под ф-ционал getline - и вся любовь. А хотелось бы парсер где удобно/комфортно работать (примеры выше приводил)

Не по теме:

Цитата Сообщение от XLAT Посмотреть сообщение
такая уверенная аргументация мне будет полезна.
Если спокойно обдумаете каждый аргумент - будет

0
Покинул чат.
1132 / 727 / 195
Регистрация: 30.03.2021
Сообщений: 2,379
08.12.2025, 15:50
Пытаюсь смотреть STL ranges, поэтому набросок в таком плане:
(не вариант решения, а скорее просьба к спецам показать, как такое пишется )
Кликните здесь для просмотра всего текста

Без удаления лишних пробелов, "\n" и тп. Просто набросок. Видимо, это будет медленнее, чем варианты выше.
Тут в каждом for повтор. код - можно вынести в одну функцию.
Так же вместо for наверное можно использовать что-то вроде std::transform и писать в "линеечку" через "|"
но я пока не настолько знаю STL (что бы еще не преобразовывать результат std::views::split в std::string_view для
следующего разбиения)
Если бы кто из спецов написал нормально в таком виде, -как учебный пример... Но они врядли обратят внимание

с++20
str - это текст для парсинга.
C++
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
       for(const auto &face : str | std::views::split('f')) {
            if(face.empty()) continue;
            //создать контейнер для набора face
            std::string_view face_str(face.begin(), face.end());
            //std::cout << "Face:" << face_str << ";\n";
 
            for(const auto &vertex : face_str | std::views::split(' ')) {
                if(vertex.empty()) continue;
                //создать контейнер для набора vertex
                std::string_view vertex_str(vertex.begin(), vertex.end());
                //std::cout << "  Vertex:" << vertex_str << ";\n";
                
                std::string slash=" ";
                if(vertex_str.find("//") !=std::string::npos)
                    slash="//";
                else if(vertex_str.find("/") !=std::string::npos)    
                    slash="/";
                 
                for(const auto &value : vertex_str | std::views::split(slash)) {
                    if(value.empty()) continue;
                    std::string_view value_str(value.begin(), value.end());
                    //std::cout << "    Value:" << value_str << ";\n";
                    //преобразовать строки в числовые значения
                    //создать сущность vertex, заполнить его value и запихнуть в контейнер 
                }
            }
0
Just Do It!
 Аватар для XLAT
4202 / 2660 / 654
Регистрация: 23.09.2014
Сообщений: 9,019
Записей в блоге: 3
08.12.2025, 17:54
Цитата Сообщение от Igor3D Посмотреть сообщение
Если спокойно обдумаете каждый аргумент - будет
умные проигрывают дуракам, потому что много(а значит долго) думают))

Цитата Сообщение от Igor3D Посмотреть сообщение
getline
вместо думанья я убрал ваш ненавистный гетлайн там где грабятся числа:

C++
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
const char* const NAMEPROJ{"DEMO::Obj-Loader::version-0.5"};
///----------------------------------------------------------------------------|
/// C++20
/// source code: UTF-8
/// Файл "cube.obj": https://github.com/garykac/3d-cubes/blob/master/cube.obj
///----------------------------------------------------------------------------|
#include <iostream>
#include <charconv>
#include <sstream>
#include <fstream>
#include <vector>
#include <format>
 
#define l(a) std::cout << #a << " = " << (a) << '\n';
 
///---------|
/// my lib  |
///---------:
namespace myl
{
    template <typename... T> void banner(T&&... vals)
    {   ((std::cout << vals << std::endl), ...);
    }
 
    template<typename T>
    static std::streamsize getStreamSize(T& stream)
    {
        std::streampos current_pos = stream.tellg();
 
        stream.seekg(0, std::ios::end);
        std::streampos end_pos = stream.tellg();
 
        stream.seekg(current_pos);
        return end_pos;
    }
}
 
 
///----------------------------------------------------------------------------|
/// Генератор входных данных.
///-------------------------------------------------------------------- GenTest:
struct GenTest
{   static std::string get(int n = 1)
    {   constexpr const char* ss
        {
            /*01*/ "# A 2 x 2 square mapped with a 1 x 1 square\n"
            /*02*/ "# texture stretched to fit the square exactly.\n"
            /*03*/ "mtllib master.mtl\n"
            /*04*/ "#---------------------------\n"
            /*05*/ "v 0.100000 2.200000 0.300000\n"
            /*06*/ "v 0.100000 0.200000 0.300000\n"
            /*07*/ "v 2.100000 0.200000 0.300000\n"
            /*08*/ "v 2.100000 2.200000 0.300000\n"
            /*09*/ "vt 0.04    0.040000\n"
            /*10*/ "vt 1.00    0.040000\n"
            /*11*/ "vt 1.00    1.000000\n"
            /*12*/ "vt 0.04 \t 1.000000\n"
            /*13*/ "#---------------------------\n"
            /*14*/ "# 4 vertices\n"
            /*15*/ "usemtl wood\n"
            /*16*/ "# The first number is point and second is texture point\n"
            /*17*/ "f 1/1 2/2 3/3 4/4 #qwerty\n"
            /*18*/ "# 1 element\n"
        };
 
        constexpr size_t len = std::char_traits<char>::length(ss);
        l(len)
 
        std::string s;
        while (n--) s += ss;
        return      s;
    }
};
 
 
///----------------------------------------------------------------------------|
/// Хранилища для Вертексов и Индексов.
///---------------------------------------------------------------------- BaseV:
template<typename T>
struct BaseV : std::array<std::vector<T>, 3>
{   enum EFACE
    {    POS,
         UV ,
         NORM
    };
 
    void reserve(size_t n)
    {   for(auto& m : *this) { m.clear(); m.reserve(n); }
    }
};
 
struct Face   : BaseV<int  > { };
struct Vertex : BaseV<float> { };
 
 
using cvf_t = const std::vector<float>;
void  out(std::ostream& o, cvf_t& m, std::string_view s, const size_t step)
{
    if (m.empty()) return;
    for(    size_t i = 0; i < m.size();)
    {   o << s;
        for(size_t j = 0; j < step && i < m.size(); ++j, ++i)
        {   o << std::format("{:6}", m[i]);
        }   o << '\n';
    }       o << '\n';
}
 
std::ostream& operator<<(std::ostream& o, const Vertex& v)
{   out(o, v[Vertex::POS ], "v  ---> ", 3);
    out(o, v[Vertex::UV  ], "vt ---> ", 2);
    out(o, v[Vertex::NORM], "vn ---> ", 3);
    return o;
}
 
std::ostream& operator<<(std::ostream& o, const Face& f)
{   o << "f-v : "; for(const auto n : f[Face::POS ]) {o << n << ' ';} o << '\n';
    o << "f-vt: "; for(const auto n : f[Face::UV  ]) {o << n << ' ';} o << '\n';
    o << "f-vn: "; for(const auto n : f[Face::NORM]) {o << n << ' ';} o << '\n';
    return o;
}
 
template<typename T>
std::ostream& operator<<(std::ostream& o, const std::vector<T>& v)
{   for(const auto n : v) o << n << ", "; return o;
}
 
 
///----------------------------------------------------------------------------|
/// ObjLoader
///------------------------------------------------------------------ ObjLoader:
struct  ObjLoader ; std::ostream& operator<<(std::ostream&, const ObjLoader&);
struct  ObjLoader : Face, Vertex
{       ObjLoader()
        {
        }
 
    std::string name;
 
    ///------------------------------|
    /// Получить данные о Vertex.    |
    ///------------------------------:
    const std::vector<float>& get(Vertex::BaseV::EFACE i) const
    {   return (*static_cast<const Vertex*>(this))[size_t(i)];
    }
 
    ///------------------------------|
    /// Получить данные об индексах. |
    ///------------------------------:
    const std::vector<int>& get(Face::BaseV::EFACE i) const
    {   return (*static_cast<const Face*>(this))[size_t(i)];
    }
 
    void go(std::istream& is)
    {
        if(!is.good())
        {   std::cout << "ERROR: В потоке ничего нет ...\n";
            throw(1u);
        }
 
        cnt = 2;
 
        Face  & F = *this;
        Vertex& V = *this;
        {
            const size_t sz = myl::getStreamSize(is);
            F.reserve   (sz / 5);
            V.reserve   (sz / 5);
        }
 
        std::getline(is, name);
 
        for(std::string s; std::getline(is, s); ++cnt)
        {
            if(s[0] != 'f')
            {
                const std::string_view a{s.substr(0, 2)};
 
                     if(a == "v ") go3d(s, V[Vertex::POS ]);
                else if(a == "vn") go3d(s, V[Vertex::NORM]);
                else if(a == "vt") go3d(s, V[Vertex::UV  ]);
                continue;
            }
 
            std::stringstream is(s); is >> s;
 
            while( is >> s && s[0] != '#' )
            {   parseNumbers(s);
            }
        }
    }
 
    void go3d(std::string_view ss, std::vector<float>& res)
    {
        std::string s; std::stringstream is(ss.data()); is >> s;
 
        while(is >> s && s[0] != '#')
        {
            try
            {   size_t  d;
                res.push_back(std::stod(s, &d));
                if(d != s.size())    throw(cnt);
            }
            catch(...)
            {   throw(cnt);
            }
        }
    }
 
    void parseNumbers(std::string_view s)
    {
        Face& F = *this;
        const char* curr = &s.front();
        const char* end  = curr + s.size();
 
        for(size_t i{}; ; ++i, ++curr)
        {
            if(i  > 2) throw(cnt);
            if(i == 1 && *curr == '/') continue;
 
            F[i].push_back(0);
            auto res     = std::from_chars(curr, end, F[i].back());
            if(  res.ec != std::errc ()) throw(cnt);
            if( (curr = res.ptr) == end) break;
            if( *curr   != '/' )         throw(cnt);
        }
    }
 
    static void test(std::istream&& is = std::stringstream(GenTest::get()))
    {
        try
        {   ObjLoader    objLoader;
            objLoader.go(is);
            std::cout << objLoader << '\n';
 
            l(objLoader.get(Vertex::POS ))
            l(objLoader.get(Vertex::UV  ))
            l(objLoader.get(Vertex::NORM))
            l(objLoader.get(Face  ::POS ))
        }
        catch(unsigned cnt)
        {   std::cout << std::format("ERROR: ObjLoader line={}...\n\n", cnt);
            return;
        }
 
        myl::banner(
        "///--------------------------|",
        "/// Тестирование УСПЕШНО!    |",
        "///--------------------------|\n");
    }
 
private:
    unsigned cnt;
};
 
std::ostream& operator<<(std::ostream& o, const ObjLoader& obj)
{          o << std::format("{}\n\n", obj.name);
           o << (Vertex)(obj);
           o << (Face  )(obj);
    return o;
}
 
 
///----------------------------------------------------------------------------|
/// main
///----------------------------------------------------------------------- main:
int main()
{
    std::system        (  "chcp 65001>0");
    std::locale::global(std::locale("C"));
 
    std::cout
    <<  "///-----------------------------------------------|\n"
    <<  "/// Привет, я есть "     << NAMEPROJ <<        "  |\n"
    <<  "///-----------------------------------------------|\n\n";
 
/// ObjLoader::test(std::ifstream("cube.obj"));
    ObjLoader::test();
 
    std::cout << "ПРОГРАММА ЗАВЕРШИЛА РАБОТУ." << std::endl;
    std::cin.get();
}
0
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,852
Записей в блоге: 2
09.12.2025, 16:28  [ТС]
Вот фрагмент по нашей теме, читает тройку индексов
Цитата Сообщение от XLAT Посмотреть сообщение
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void parseNumbers(std::string_view s)
    {
        Face& F = *this;
        const char* curr = &s.front();
        const char* end  = curr + s.size();
        for(size_t i{}; ; ++i, ++curr)
        {
            if(i  > 2) throw(cnt);
            if(i == 1 && *curr == '/') continue;
            F[i].push_back(0);
            auto res     = std::from_chars(curr, end, F[i].back());
            if(  res.ec != std::errc ()) throw(cnt);
            if( (curr = res.ptr) == end) break;
            if( *curr   != '/' )         throw(cnt);
        }
    }
Допустим др программист не знает правил .obj файла изложенных в стартовом посте. Что он может понять из этого кода? Да ничего, не говоря уже о том чтобы что-то переделать, улучшить. Впрочем это непросто даже зная правила. Получается (слишком) сложно для, в общем-то, совсем несложной задачки. Нужно как-то упростить код, тогда он сам станет изящнее.

Да, но как это сделать? Попробуем аккуратнее все расписать, добавим примечания и выдачу ошибок (аттач). Получше (на мой взгляд ), но принципиально проблему не решает, все равно надо "вникать" гораздо больше чем хотелось бы.

Какие есть предложения?
Вложения
Тип файла: zip ParseFace.cpp.zip (1.7 Кб, 11 просмотров)
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2872 / 1042
Регистрация: 01.06.2021
Сообщений: 10,512
10.12.2025, 00:43
Цитата Сообщение от Igor3D Посмотреть сообщение
Допустим др программист не знает правил .obj файла изложенных в стартовом посте.
а что мешает читать документацию формата
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.12.2025, 00:43
Помогаю со студенческими работами здесь

Разбор строки
Здравствуйте. В stdin программы приходит строка вида domain=d.ru&amp;type=delete&amp;file=std&amp;... При...

Интерпретатор выражений с переменной(разбор и анализ строки))
Может у кого есть библиотечка по данному сабжу? В идеале надо чтобы пользователь мог вводить любую...

Консоль, разбор командной строки
#include &lt;iostream&gt; int main(int ArgumentsCount, char **Arguments) { char **p; char **l; ...

Разбор строки
Помогите разобрать вот такие строки: 2011/07/01 22:08:29 1...

Разбор сложной строки с аргументами
Здравствуйте друзья! Мне кажеться я заблудился в этой жизни(( В мою длл через пайп поступает...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru