Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Программирование [игнор отключен] [закрыт для гостей] / 3D C# GDI / 6 сообщений из 6, страница 1 из 1
14.01.2013, 13:48
    #38109172
RomanH
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
3D C# GDI
Товарищи! никто не встречал простую библиотеку(фрэймоворк)
для отрисовки простейшей 3D графики средствами GDI+ для C# (OpenGL и DirectX пока рано изучать).
Хочется самому понять и построить видовую матрицу для перемещения FPS камеры.

Нужно понять что такое мировая, видовая, проекционная матрица на простом примере.
И как перемножая координаты вектора на матрицу происходят изменения в координатах вектора.
...
Рейтинг: 0 / 0
15.01.2013, 15:21
    #38110833
pirovindos
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
3D C# GDI
RomanH,
А вариант рассчитывать 2D картинку в нужной проекции самому, почему не подходит? Хочется сравнить?
...
Рейтинг: 0 / 0
15.01.2013, 15:46
    #38110890
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
3D C# GDI
По поисковым тегам: 3D graphics, open, framework e.t.c. гуглится
бесконечное количество сорцов и библиотек. GDI+ тебе нафик
не нужен (ведь ты изучаешь основы). Изучишь - потом легко
перенесёшь знания на ОпенЖЛ и всё остальное.
...
Рейтинг: 0 / 0
15.01.2013, 22:23
    #38111506
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
3D C# GDI
RomanHOpenGL и DirectX пока рано изучать
зря
...
Рейтинг: 0 / 0
24.01.2013, 05:21
    #38122590
Пётр Седов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
3D C# GDI
2 RomanH:

RomanHOpenGL и DirectX пока рано изучать
Изучить OpenGL на начальном уровне -- несложно, особенно если использовать библиотеки вроде GLUT или SDL, которые сильно упрощают создание окна и инициализацию OpenGL, избавляя программиста от возни с низко-уровневыми деталями.

RomanHХочется самому понять и построить видовую матрицу для перемещения FPS камеры.

Нужно понять что такое мировая, видовая, проекционная матрица на простом примере.
И как перемножая координаты вектора на матрицу происходят изменения в координатах вектора.
Вот, написал простой пример, который поможет разобраться с матрицами в 3D-графике. Правда, компилятора C# под рукой не было, поэтому написал на C++. Портирование C++/GDI -> C#/GDI+ должно быть механическим, так как используются только базовые возможности C++. Ну или можно не заморачиваться на портирование, а разобраться с матрицами не отходя от C++.

gdi_3d.cpp:
Код: plaintext
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.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
#include <assert.h>
#include <math.h>
#include <float.h>
#define NOMINMAX
#include <windows.h>

const float _undef_float = -FLT_MAX;

// градусы -> радианы
inline float rad_from_deg(float angle) {
  return static_cast<float>(3.141592653589793 / 180) * angle;
}

inline int round(float x) {
  return static_cast<int>(floor(x + 0.5F));
}

struct Vec_3 {
  float x, y, z;
};

inline Vec_3 v3(float x, float y, float z) {
  Vec_3 res = {x, y, z};
  return res;
}

inline Vec_3 normalize(Vec_3 v) {
  float len = sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
  assert(len != 0);
  return v3(v.x / len, v.y / len, v.z / len);
}

// векторное произведение (cross product)
// может быть записано как определитель (determinant):
// |i  j  k |
// |ax ay az|
// |bx by bz|
inline Vec_3 cross(Vec_3 a, Vec_3 b) {
  return v3(
    /*x:*/ a.y * b.z - b.y * a.z,
    /*y:*/ a.z * b.x - b.z * a.x,
    /*z:*/ a.x * b.y - b.x * a.y
  );
}

struct Matrix {
  float elems[4][4];
};

// единичная матрица, см. glLoadIdentity
const Matrix _identity = {{
  {1, 0, 0, 0},
  {0, 1, 0, 0},
  {0, 0, 1, 0},
  {0, 0, 0, 1},
}};

// перемножает 2 матрицы
Matrix* mul(Matrix* res, const Matrix* a, const Matrix* b) {
  assert(res != a);
  assert(res != b);
  for (int row = 0; row < 4; row++) {
    for (int col = 0; col < 4; col++) {
      float e = 0;
      for (int i = 0; i < 4; i++) {
        e += a->elems[row][i] * b->elems[i][col];
      }
      res->elems[row][col] = e;
    }
  }
  return res;
}

// перемножает 3 матрицы
Matrix* mul(Matrix* res, const Matrix* a, const Matrix* b, const Matrix* c) {
  Matrix t;
  return mul(res, mul(&t, a, b), c);
}

// параллельный перенос, см. glTranslate
Matrix* translate(Matrix* res, Vec_3 v) {
  Matrix m = {{
    {1, 0, 0, v.x},
    {0, 1, 0, v.y},
    {0, 0, 1, v.z},
    {0, 0, 0, 1  },
  }};
  *res = m;
  return res;
}

// поворот вокруг оси z, см. glRotate (умеет вокруг любой оси)
Matrix* rotate_z(Matrix* res, float angle) {
  float c = cos(rad_from_deg(angle));
  float s = sin(rad_from_deg(angle));
  Matrix m = {{
    {c, -s, 0, 0},
    {s, c,  0, 0},
    {0, 0,  1, 0},
    {0, 0,  0, 1},
  }};
  *res = m;
  return res;
}

// мировые координаты -> камерные координаты, см. gluLookAt
// cam_pos, target_pos - в мировых координатах
Matrix* look_at(Matrix* res, Vec_3 cam_pos, Vec_3 target_pos) {
  Matrix m1;
  translate(&m1, v3(-cam_pos.x, -cam_pos.y, -cam_pos.z));

  // оси камеры в мировых координатах
  Vec_3 dir = normalize(v3(target_pos.x - cam_pos.x, target_pos.y - cam_pos.y, target_pos.z - cam_pos.z));
  Vec_3 right = normalize(v3(target_pos.y - cam_pos.y, -(target_pos.x - cam_pos.x), 0));
  Vec_3 up = cross(right, dir);
  Matrix m2 = {{
    {right.x, right.y, right.z, 0},
    {up.x,    up.y,    up.z,    0},
    {-dir.x,  -dir.y,  -dir.z,  0},
    {0,       0,       0,       1},
  }};

  return mul(res, &m2, &m1);
}

//----------------

bool _running = false;

void init_window();
void term_window();

int main() {
  init_window();

  _running = true;
  // главный цикл
  while (_running) {
    MSG m;
    GetMessage(&m, /*hWnd:*/NULL, /*wMsgFilterMin:*/0, /*wMsgFilterMax:*/0);
    TranslateMessage(&m);
    DispatchMessage(&m);
  }

  term_window();

  return 0;
}

const char* const _window_class_name = "gdi_3d";
ATOM _window_class_id = 0;
HWND _window_han = NULL;
// размеры клиентской области окна (client area)
int _window_client_width = -1;
int _window_client_height = -1;

LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

void init_window() {
  HINSTANCE exe_han = GetModuleHandle(NULL);

  // регистрируем оконный класс
  assert(_window_class_id == 0);
  WNDCLASSEX wc_params;
  wc_params.cbSize = sizeof(WNDCLASSEX);
  wc_params.style = CS_HREDRAW | CS_VREDRAW; // полная перерисовка клиентской области окна при изменении размеров
  wc_params.lpfnWndProc = &window_proc;
  wc_params.cbClsExtra = 0;
  wc_params.cbWndExtra = 0;
  wc_params.hInstance = exe_han;
  wc_params.hIcon = NULL;
  wc_params.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc_params.hbrBackground = NULL; // фон будем рисовать сами
  wc_params.lpszMenuName = NULL;
  wc_params.lpszClassName = _window_class_name;
  wc_params.hIconSm = NULL;
  _window_class_id = RegisterClassEx(&wc_params);

  // создаём окно
  assert(_window_han == NULL);
  _window_han = CreateWindowEx(
    /*dwExStyle:*/0,
    /*lpClassName:*/_window_class_name,
    /*lpWindowName:*/"GDI 3D", // заголовок окна
    /*dwStyle:*/WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    /*x:*/CW_USEDEFAULT,
    /*y:*/CW_USEDEFAULT,
    /*nWidth:*/CW_USEDEFAULT,
    /*nHeight:*/CW_USEDEFAULT,
    /*hWndParent:*/NULL,
    /*hMenu:*/NULL,
    /*hInstance:*/exe_han,
    /*lpParam:*/NULL
  );
}

void term_window() {
  if (_window_han != NULL) {
    DestroyWindow(_window_han);
    _window_han = NULL;
  }

  if (_window_class_id != 0) {
    HINSTANCE exe_han = GetModuleHandle(NULL);
    UnregisterClass(_window_class_name, exe_han);
    _window_class_id = 0;
  }
}

void request_paint() {
  assert(_window_han != NULL);
  // помечаем всю клиентскую область окна как требующую перерисовки
  InvalidateRect(_window_han, /*lpRect:*/NULL, /*bErase:*/false);
  // в ближайшее время система пришлёт нашему окну сообщение WM_PAINT
}

// сферические координаты камеры
float _cam_azim = 270;
float _cam_height = 40;
float _cam_dist = 1000;

enum Proj_Type {_proj_type_perspective, _proj_type_parallel};
Proj_Type _proj_type = _proj_type_perspective;

Vec_3 _car_pos = {0, 0, 0};
float _car_dir = 0;

void key_down(int key) {
  switch (key) {
  // управление камерой
  case VK_LEFT:
    _cam_azim -= 10;
    request_paint();
    break;
  case VK_RIGHT:
    _cam_azim += 10;
    request_paint();
    break;
  case VK_DOWN: {
    float h = _cam_height - 10;
    if (h > -90) {
      _cam_height = h;
      request_paint();
    }
    break;
  }
  case VK_UP: {
    float h = _cam_height + 10;
    if (h < 90) {
      _cam_height = h;
      request_paint();
    }
    break;
  }
  case VK_ADD: {
    float d = _cam_dist - 10;
    if (d > 0) {
      _cam_dist = d;
      request_paint();
    }
    break;
  }
  case VK_SUBTRACT:
    _cam_dist += 10;
    request_paint();
    break;
  case 'P':
    // меняем тип проекции
    switch (_proj_type) {
    case _proj_type_perspective: _proj_type = _proj_type_parallel; break;
    case _proj_type_parallel: _proj_type = _proj_type_perspective; break;
    default: assert(false);
    }
    request_paint();
    break;
  // управление машиной
  case 'A':
    _car_dir += 10;
    request_paint();
    break;
  case 'D':
    _car_dir -= 10;
    request_paint();
    break;
  case 'W':
    _car_pos.x += 10 * cos(rad_from_deg(_car_dir));
    _car_pos.y += 10 * sin(rad_from_deg(_car_dir));
    request_paint();
    break;
  case 'S':
    _car_pos.x -= 10 * cos(rad_from_deg(_car_dir));
    _car_pos.y -= 10 * sin(rad_from_deg(_car_dir));
    request_paint();
    break;
  }
}

bool _double_buffered = true;
HDC _gdi_context = NULL;

void render_scene();

// оконная процедура (указывается при регистрации оконного класса)
LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  switch (uMsg) {
  case WM_CLOSE:
    // завершаем главный цикл
    _running = false;
    return 0;
  case WM_SIZE:
    _window_client_width = LOWORD(lParam);
    _window_client_height = HIWORD(lParam);
    return 0;
  case WM_KEYDOWN:
    key_down(/*key:*/wParam);
    return 0;
  case WM_ERASEBKGND:
    // здесь ничего не делаем, фон рисуется в функции render_scene
    return false; // не нарисовали фон
  case WM_PAINT: {
    PAINTSTRUCT ps;
    BeginPaint(hwnd, &ps);
    if (_double_buffered) {
      int x = ps.rcPaint.left;
      int y = ps.rcPaint.top;
      int w = ps.rcPaint.right - ps.rcPaint.left;
      int h = ps.rcPaint.bottom - ps.rcPaint.top;
      if ((w > 0) && (h > 0)) {
        // рисуем сцену в back buffer
        HBITMAP back_buf = CreateCompatibleBitmap(ps.hdc, w, h);
        assert(_gdi_context == NULL);
        _gdi_context = CreateCompatibleDC(ps.hdc);
        SelectObject(_gdi_context, back_buf);
        SetViewportOrgEx(_gdi_context, -x, -y, NULL);
        render_scene();

        // копируем содержимое back buffer-а в окно
        BitBlt(ps.hdc, x, y, w, h, _gdi_context, x, y, SRCCOPY);

        DeleteDC(_gdi_context);
        _gdi_context = NULL;
        DeleteObject(back_buf);
      }
    } else {
      // рисуем сцену прямо в окно
      assert(_gdi_context == NULL);
      _gdi_context = ps.hdc;
      render_scene();
      _gdi_context = NULL;
    }
    EndPaint(hwnd, &ps);
    return 0;
  }
  default:
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
  }
}

Matrix _world_transform = _identity; // локальные координаты объекта -> мировые координаты
Matrix _view_transform = _identity; // мировые координаты -> камерные координаты
Matrix _proj_transform = _identity; // камерные координаты -> координаты для отсечения

void update_proj_transform() {
  if ((_window_client_width <= 0) || (_window_client_height <= 0)) return;
  switch (_proj_type) {
  case _proj_type_perspective: { // см. gluPerspective
    const float max_fov = 90; // максимальный угол обзора (field of view)
    float h; // тангенс половины угла обзора по горизонтали
    float v; // тангенс половины угла обзора по вертикали
    if (_window_client_width > _window_client_height) {
      h = tan(rad_from_deg(0.5F * max_fov));
      v = _window_client_height * h / _window_client_width;
    } else {
      v = tan(rad_from_deg(0.5F * max_fov));
      h = _window_client_width * v / _window_client_height;
    }
    Matrix m = {{
      {1 / h, 0,     0,  0},
      {0,     1 / v, 0,  0},
      {0,     0,     1,  0}, // эта строка будет другая при использовании OpenGL
      {0,     0,     -1, 0},
    }};
    _proj_transform = m;
    break;
  }
  case _proj_type_parallel: {
    const float max_size = 2000; // максимальный размер проекции (в мировых единицах)
    float h; // половина размера проекции по горизонтали
    float v; // половина размера проекции по вертикали
    if (_window_client_width > _window_client_height) {
      h = 0.5F * max_size;
      v = _window_client_height * h / _window_client_width;
    } else {
      v = 0.5F * max_size;
      h = _window_client_width * v / _window_client_height;
    }
    Matrix m = {{
      {1 / h, 0,     0, 0},
      {0,     1 / v, 0, 0},
      {0,     0,     1, 0}, // эта строка будет другая при использовании OpenGL
      {0,     0,     0, 1},
    }};
    _proj_transform = m;
    break;
  }
  default: assert(false);
  }
}

void update_view_transform() {
  // сферические координаты -> декартовы координаты
  Vec_3 cam_pos;
  cam_pos.x = _car_pos.x + _cam_dist * cos(rad_from_deg(_cam_height)) * cos(rad_from_deg(_cam_azim));
  cam_pos.y = _car_pos.y + _cam_dist * cos(rad_from_deg(_cam_height)) * sin(rad_from_deg(_cam_azim));
  cam_pos.z = _car_pos.z + _cam_dist * sin(rad_from_deg(_cam_height));

  look_at(&_view_transform, cam_pos, /*target_pos:*/_car_pos);
}

struct Edge;
struct Model {
  const Vec_3* verts;
  int verts_count;
  const Edge* edges;
  int edges_count;
};

struct Edge {
  int vert_1_index;
  int vert_2_index;
};

#include "models.cpp"

void render_model(const Model* model);

void render_scene() {
  assert(_gdi_context != NULL);

  // рисуем фон
  RECT r = {0, 0, _window_client_width, _window_client_height};
  HBRUSH b = static_cast<HBRUSH>(GetStockObject(GRAY_BRUSH));
  FillRect(_gdi_context, &r, b);

  update_proj_transform();
  update_view_transform();

  _world_transform = _identity;
  render_model(&_grid_model);

  Matrix t1, t2;
  mul(&_world_transform, translate(&t2, _car_pos), rotate_z(&t1, _car_dir));
  render_model(&_car_model);
}

void render_model(const Model* model) {
  assert(_gdi_context != NULL);

  // собираем все преобразования координат в одно
  Matrix m;
  mul(&m, &_proj_transform, &_view_transform, &_world_transform);

  // проецируем все вершины
  struct Transformed_Vert {
    float x, y; // в пикселах
  };
  const Vec_3* verts = model->verts;
  int verts_count = model->verts_count;
  Transformed_Vert* transformed_verts = new Transformed_Vert[verts_count];
  for (int i = 0; i < verts_count; i++) {
    const Vec_3* v = &verts[i]; // в локальных координатах объекта
    Transformed_Vert* tv = &transformed_verts[i];

    // вычисляем координаты для отсечения (clip coordinates)
    float xc = m.elems[0][0] * v->x + m.elems[0][1] * v->y + m.elems[0][2] * v->z + m.elems[0][3];
    float yc = m.elems[1][0] * v->x + m.elems[1][1] * v->y + m.elems[1][2] * v->z + m.elems[1][3];
  #if 0
    float zc = m.elems[2][0] * v->x + m.elems[2][1] * v->y + m.elems[2][2] * v->z + m.elems[2][3];
  #endif
    float wc = m.elems[3][0] * v->x + m.elems[3][1] * v->y + m.elems[3][2] * v->z + m.elems[3][3];

    if (wc > 0) {
      // вычисляем нормализованные координаты устройства (normalized device coordinates)
      float xn = xc / wc;
      float yn = yc / wc;
      // во viewport-е видны точки, у которых  -1 <= xn <= 1  и  -1 <= yn <= 1

      tv->x = (0.5F + 0.5F * xn) * _window_client_width;
      tv->y = (0.5F - 0.5F * yn) * _window_client_height; // в GDI, ось y идёт вниз
    } else {
      tv->x = _undef_float;
      tv->y = _undef_float;
    }
  }

  // рисуем рёбра
  HPEN p = static_cast<HPEN>(GetStockObject(WHITE_PEN));
  SelectObject(_gdi_context, p);
  const Edge* edges = model->edges;
  int edges_count = model->edges_count;
  for (int i = 0; i < edges_count; i++) {
    const Edge* e = &edges[i];
    const Transformed_Vert* tv1 = &transformed_verts[e->vert_1_index];
    const Transformed_Vert* tv2 = &transformed_verts[e->vert_2_index];
    if ((tv1->x == _undef_float) || (tv2->x == _undef_float)) continue;
    // насколько я знаю, GDI+ поддерживает координаты типа float, поэтому там округлять не надо
    MoveToEx(_gdi_context, round(tv1->x), round(tv1->y), NULL);
    LineTo(_gdi_context, round(tv2->x), round(tv2->y));
  }

  delete[] transformed_verts;
}


models.cpp:
Код: plaintext
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.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
627.
628.
629.
630.
631.
632.
633.
634.
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647.
648.
649.
650.
651.
652.
653.
654.
655.
656.
657.
658.
659.
660.
661.
662.
663.
664.
665.
666.
667.
668.
669.
670.
671.
672.
673.
674.
675.
676.
677.
678.
679.
680.
681.
682.
683.
684.
685.
686.
687.
688.
689.
690.
691.
692.
693.
694.
695.
696.
697.
698.
699.
700.
701.
702.
703.
704.
705.
706.
707.
708.
709.
710.
711.
712.
713.
714.
715.
716.
717.
718.
719.
720.
721.
722.
723.
724.
725.
726.
727.
728.
729.
730.
731.
732.
733.
734.
735.
736.
737.
738.
739.
740.
741.
742.
const Vec_3 _grid_verts[121] = {
{-2000.0, -2000.0, 0.0},
{-1600.0, -2000.0, 0.0},
{-1200.0, -2000.0, 0.0},
{-800.0, -2000.0, 0.0},
{-400.0, -2000.0, 0.0},
{0.0, -2000.0, 0.0},
{400.0, -2000.0, 0.0},
{800.0, -2000.0, 0.0},
{1200.0, -2000.0, 0.0},
{1600.0, -2000.0, 0.0},
{2000.0, -2000.0, 0.0},
{-2000.0, -1600.0, 0.0},
{-1600.0, -1600.0, 0.0},
{-1200.0, -1600.0, 0.0},
{-800.0, -1600.0, 0.0},
{-400.0, -1600.0, 0.0},
{0.0, -1600.0, 0.0},
{400.0, -1600.0, 0.0},
{800.0, -1600.0, 0.0},
{1200.0, -1600.0, 0.0},
{1600.0, -1600.0, 0.0},
{2000.0, -1600.0, 0.0},
{-2000.0, -1200.0, 0.0},
{-1600.0, -1200.0, 0.0},
{-1200.0, -1200.0, 0.0},
{-800.0, -1200.0, 0.0},
{-400.0, -1200.0, 0.0},
{0.0, -1200.0, 0.0},
{400.0, -1200.0, 0.0},
{800.0, -1200.0, 0.0},
{1200.0, -1200.0, 0.0},
{1600.0, -1200.0, 0.0},
{2000.0, -1200.0, 0.0},
{-2000.0, -800.0, 0.0},
{-1600.0, -800.0, 0.0},
{-1200.0, -800.0, 0.0},
{-800.0, -800.0, 0.0},
{-400.0, -800.0, 0.0},
{0.0, -800.0, 0.0},
{400.0, -800.0, 0.0},
{800.0, -800.0, 0.0},
{1200.0, -800.0, 0.0},
{1600.0, -800.0, 0.0},
{2000.0, -800.0, 0.0},
{-2000.0, -400.0, 0.0},
{-1600.0, -400.0, 0.0},
{-1200.0, -400.0, 0.0},
{-800.0, -400.0, 0.0},
{-400.0, -400.0, 0.0},
{0.0, -400.0, 0.0},
{400.0, -400.0, 0.0},
{800.0, -400.0, 0.0},
{1200.0, -400.0, 0.0},
{1600.0, -400.0, 0.0},
{2000.0, -400.0, 0.0},
{-2000.0, 0.0, 0.0},
{-1600.0, 0.0, 0.0},
{-1200.0, 0.0, 0.0},
{-800.0, 0.0, 0.0},
{-400.0, 0.0, 0.0},
{0.0, 0.0, 0.0},
{400.0, 0.0, 0.0},
{800.0, 0.0, 0.0},
{1200.0, 0.0, 0.0},
{1600.0, 0.0, 0.0},
{2000.0, 0.0, 0.0},
{-2000.0, 400.0, 0.0},
{-1600.0, 400.0, 0.0},
{-1200.0, 400.0, 0.0},
{-800.0, 400.0, 0.0},
{-400.0, 400.0, 0.0},
{0.0, 400.0, 0.0},
{400.0, 400.0, 0.0},
{800.0, 400.0, 0.0},
{1200.0, 400.0, 0.0},
{1600.0, 400.0, 0.0},
{2000.0, 400.0, 0.0},
{-2000.0, 800.0, 0.0},
{-1600.0, 800.0, 0.0},
{-1200.0, 800.0, 0.0},
{-800.0, 800.0, 0.0},
{-400.0, 800.0, 0.0},
{0.0, 800.0, 0.0},
{400.0, 800.0, 0.0},
{800.0, 800.0, 0.0},
{1200.0, 800.0, 0.0},
{1600.0, 800.0, 0.0},
{2000.0, 800.0, 0.0},
{-2000.0, 1200.0, 0.0},
{-1600.0, 1200.0, 0.0},
{-1200.0, 1200.0, 0.0},
{-800.0, 1200.0, 0.0},
{-400.0, 1200.0, 0.0},
{0.0, 1200.0, 0.0},
{400.0, 1200.0, 0.0},
{800.0, 1200.0, 0.0},
{1200.0, 1200.0, 0.0},
{1600.0, 1200.0, 0.0},
{2000.0, 1200.0, 0.0},
{-2000.0, 1600.0, 0.0},
{-1600.0, 1600.0, 0.0},
{-1200.0, 1600.0, 0.0},
{-800.0, 1600.0, 0.0},
{-400.0, 1600.0, 0.0},
{0.0, 1600.0, 0.0},
{400.0, 1600.0, 0.0},
{800.0, 1600.0, 0.0},
{1200.0, 1600.0, 0.0},
{1600.0, 1600.0, 0.0},
{2000.0, 1600.0, 0.0},
{-2000.0, 2000.0, 0.0},
{-1600.0, 2000.0, 0.0},
{-1200.0, 2000.0, 0.0},
{-800.0, 2000.0, 0.0},
{-400.0, 2000.0, 0.0},
{0.0, 2000.0, 0.0},
{400.0, 2000.0, 0.0},
{800.0, 2000.0, 0.0},
{1200.0, 2000.0, 0.0},
{1600.0, 2000.0, 0.0},
{2000.0, 2000.0, 0.0},
};
const Edge _grid_edges[220] = {
{11, 0},
{12, 11},
{1, 12},
{0, 1},
{13, 12},
{2, 13},
{1, 2},
{14, 13},
{3, 14},
{2, 3},
{15, 14},
{4, 15},
{3, 4},
{16, 15},
{5, 16},
{4, 5},
{17, 16},
{6, 17},
{5, 6},
{18, 17},
{7, 18},
{6, 7},
{19, 18},
{8, 19},
{7, 8},
{20, 19},
{9, 20},
{8, 9},
{21, 20},
{10, 21},
{9, 10},
{22, 11},
{23, 22},
{12, 23},
{24, 23},
{13, 24},
{25, 24},
{14, 25},
{26, 25},
{15, 26},
{27, 26},
{16, 27},
{28, 27},
{17, 28},
{29, 28},
{18, 29},
{30, 29},
{19, 30},
{31, 30},
{20, 31},
{32, 31},
{21, 32},
{33, 22},
{34, 33},
{23, 34},
{35, 34},
{24, 35},
{36, 35},
{25, 36},
{37, 36},
{26, 37},
{38, 37},
{27, 38},
{39, 38},
{28, 39},
{40, 39},
{29, 40},
{41, 40},
{30, 41},
{42, 41},
{31, 42},
{43, 42},
{32, 43},
{44, 33},
{45, 44},
{34, 45},
{46, 45},
{35, 46},
{47, 46},
{36, 47},
{48, 47},
{37, 48},
{49, 48},
{38, 49},
{50, 49},
{39, 50},
{51, 50},
{40, 51},
{52, 51},
{41, 52},
{53, 52},
{42, 53},
{54, 53},
{43, 54},
{55, 44},
{56, 55},
{45, 56},
{57, 56},
{46, 57},
{58, 57},
{47, 58},
{59, 58},
{48, 59},
{60, 59},
{49, 60},
{61, 60},
{50, 61},
{62, 61},
{51, 62},
{63, 62},
{52, 63},
{64, 63},
{53, 64},
{65, 64},
{54, 65},
{66, 55},
{67, 66},
{56, 67},
{68, 67},
{57, 68},
{69, 68},
{58, 69},
{70, 69},
{59, 70},
{71, 70},
{60, 71},
{72, 71},
{61, 72},
{73, 72},
{62, 73},
{74, 73},
{63, 74},
{75, 74},
{64, 75},
{76, 75},
{65, 76},
{77, 66},
{78, 77},
{67, 78},
{79, 78},
{68, 79},
{80, 79},
{69, 80},
{81, 80},
{70, 81},
{82, 81},
{71, 82},
{83, 82},
{72, 83},
{84, 83},
{73, 84},
{85, 84},
{74, 85},
{86, 85},
{75, 86},
{87, 86},
{76, 87},
{88, 77},
{89, 88},
{78, 89},
{90, 89},
{79, 90},
{91, 90},
{80, 91},
{92, 91},
{81, 92},
{93, 92},
{82, 93},
{94, 93},
{83, 94},
{95, 94},
{84, 95},
{96, 95},
{85, 96},
{97, 96},
{86, 97},
{98, 97},
{87, 98},
{99, 88},
{100, 99},
{89, 100},
{101, 100},
{90, 101},
{102, 101},
{91, 102},
{103, 102},
{92, 103},
{104, 103},
{93, 104},
{105, 104},
{94, 105},
{106, 105},
{95, 106},
{107, 106},
{96, 107},
{108, 107},
{97, 108},
{109, 108},
{98, 109},
{110, 99},
{111, 110},
{100, 111},
{112, 111},
{101, 112},
{113, 112},
{102, 113},
{114, 113},
{103, 114},
{115, 114},
{104, 115},
{116, 115},
{105, 116},
{117, 116},
{106, 117},
{118, 117},
{107, 118},
{119, 118},
{108, 119},
{120, 119},
{109, 120},
};
const Model _grid_model = {_grid_verts, 121, _grid_edges, 220};
const Vec_3 _car_verts[164] = {
{-200.0, -100.0, 30.0},
{250.0, -100.0, 30.0},
{-200.0, 0.0, 30.0},
{250.0, 0.0, 30.0},
{-200.0, -100.0, 100.0},
{250.0, -100.0, 90.0},
{0.0, -100.0, 170.0},
{0.0, -100.0, 100.0},
{0.0, -90.0, 100.0},
{-190.0, 0.0, 100.0},
{-190.0, -90.0, 100.0},
{0.0, -90.0, 40.0},
{-190.0, -90.0, 40.0},
{100.0, -100.0, 170.0},
{120.0, -100.0, 100.0},
{-117.292, -100.0, 30.0},
{-42.7084, -100.0, 30.0},
{-59.8201, -100.0, 74.5344},
{-100.18, -100.0, 74.5344},
{-42.7084, -80.0, 30.0},
{-117.292, -80.0, 30.0},
{-59.8201, -100.0, 5.46561},
{-100.18, -100.0, 5.4656},
{-100.18, -80.0, 5.4656},
{-59.8201, -80.0, 5.46561},
{-80.0, -80.0, 2.86102e-006},
{-80.0, -100.0, 4.76837e-006},
{-114.534, -80.0, 19.8201},
{-114.534, -100.0, 19.8201},
{-45.4656, -100.0, 19.8201},
{-45.4656, -80.0, 19.8201},
{-80.0, -100.0, 80.0},
{-114.534, -100.0, 60.1799},
{-45.4656, -100.0, 60.1799},
{-120.0, -100.0, 40.0},
{-40.0, -100.0, 40.0},
{-30.0, -90.0, 40.0},
{-30.0, -70.0, 40.0},
{-130.0, -90.0, 40.0},
{-130.0, -70.0, 40.0},
{-36.832, -90.0, 65.2249},
{-123.168, -90.0, 65.2249},
{-36.832, -70.0, 65.2249},
{-123.168, -70.0, 65.2249},
{-54.7751, -90.0, 83.168},
{-54.7751, -70.0, 83.168},
{-105.225, -90.0, 83.168},
{-105.225, -70.0, 83.168},
{-80.0, -90.0, 90.0},
{-80.0, -70.0, 90.0},
{197.292, -100.0, 30.0},
{122.708, -100.0, 30.0},
{180.18, -100.0, 74.5344},
{139.82, -100.0, 74.5344},
{160.0, -100.0, 80.0},
{125.466, -100.0, 60.1799},
{194.534, -100.0, 60.1799},
{120.0, -100.0, 40.0},
{200.0, -100.0, 40.0},
{197.292, -80.0, 30.0},
{122.708, -80.0, 30.0},
{194.534, -100.0, 19.8201},
{125.466, -100.0, 19.8201},
{125.466, -80.0, 19.8201},
{194.534, -80.0, 19.8201},
{160.0, -80.0, 6.67572e-006},
{160.0, -100.0, 4.29153e-006},
{139.82, -80.0, 5.4656},
{139.82, -100.0, 5.4656},
{180.18, -80.0, 5.46562},
{180.18, -100.0, 5.46561},
{0.0, 0.0, 160.0},
{0.0, -90.0, 160.0},
{0.0, -90.0, 110.0},
{10.0, -100.0, 30.0},
{110.0, -100.0, 30.0},
{90.0, -100.0, 160.0},
{10.0, -100.0, 160.0},
{110.0, -100.0, 100.0},
{10.0, -100.0, 100.0},
{-200.0, 100.0, 30.0},
{250.0, 100.0, 30.0},
{-200.0, 100.0, 100.0},
{250.0, 100.0, 90.0},
{-200.0, 0.0, 100.0},
{250.0, 0.0, 90.0},
{0.0, 0.0, 170.0},
{0.0, 100.0, 170.0},
{0.0, 0.0, 40.0},
{0.0, 100.0, 100.0},
{0.0, 90.0, 100.0},
{-190.0, 90.0, 100.0},
{-190.0, 0.0, 40.0},
{0.0, 90.0, 40.0},
{-190.0, 90.0, 40.0},
{100.0, 0.0, 170.0},
{100.0, 100.0, 170.0},
{120.0, 0.0, 100.0},
{120.0, 100.0, 100.0},
{-117.292, 100.0, 30.0},
{-42.7084, 100.0, 30.0},
{-59.8201, 100.0, 74.5344},
{-100.18, 100.0, 74.5344},
{-42.7084, 80.0, 30.0},
{-117.292, 80.0, 30.0},
{-59.8201, 100.0, 5.46561},
{-100.18, 100.0, 5.4656},
{-100.18, 80.0, 5.4656},
{-59.8201, 80.0, 5.46561},
{-80.0, 80.0, 2.86102e-006},
{-80.0, 100.0, 4.76837e-006},
{-114.534, 80.0, 19.8201},
{-114.534, 100.0, 19.8201},
{-45.4656, 100.0, 19.8201},
{-45.4656, 80.0, 19.8201},
{-80.0, 100.0, 80.0},
{-114.534, 100.0, 60.1799},
{-45.4656, 100.0, 60.1799},
{-120.0, 100.0, 40.0},
{-40.0, 100.0, 40.0},
{-30.0, 90.0, 40.0},
{-30.0, 70.0, 40.0},
{-130.0, 90.0, 40.0},
{-130.0, 70.0, 40.0},
{-36.832, 90.0, 65.2249},
{-123.168, 90.0, 65.2249},
{-36.832, 70.0, 65.2249},
{-123.168, 70.0, 65.2249},
{-54.7751, 90.0, 83.168},
{-54.7751, 70.0, 83.168},
{-105.225, 90.0, 83.168},
{-105.225, 70.0, 83.168},
{-80.0, 90.0, 90.0},
{-80.0, 70.0, 90.0},
{197.292, 100.0, 30.0},
{122.708, 100.0, 30.0},
{180.18, 100.0, 74.5344},
{139.82, 100.0, 74.5344},
{160.0, 100.0, 80.0},
{125.466, 100.0, 60.1799},
{194.534, 100.0, 60.1799},
{120.0, 100.0, 40.0},
{200.0, 100.0, 40.0},
{197.292, 80.0, 30.0},
{122.708, 80.0, 30.0},
{194.534, 100.0, 19.8201},
{125.466, 100.0, 19.8201},
{125.466, 80.0, 19.8201},
{194.534, 80.0, 19.8201},
{160.0, 80.0, 6.67572e-006},
{160.0, 100.0, 4.29153e-006},
{139.82, 80.0, 5.4656},
{139.82, 100.0, 5.4656},
{180.18, 80.0, 5.46562},
{180.18, 100.0, 5.46561},
{0.0, 0.0, 110.0},
{0.0, 90.0, 160.0},
{0.0, 90.0, 110.0},
{10.0, 100.0, 30.0},
{110.0, 100.0, 30.0},
{90.0, 100.0, 160.0},
{10.0, 100.0, 160.0},
{110.0, 100.0, 100.0},
{10.0, 100.0, 100.0},
};
const Edge _car_edges[227] = {
{0, 2},
{3, 1},
{1, 50},
{4, 7},
{5, 85},
{84, 4},
{1, 5},
{4, 0},
{6, 13},
{86, 6},
{7, 6},
{88, 11},
{8, 7},
{8, 10},
{10, 9},
{11, 8},
{11, 36},
{12, 92},
{10, 12},
{13, 14},
{95, 13},
{14, 5},
{97, 14},
{15, 0},
{15, 34},
{17, 33},
{18, 31},
{15, 20},
{19, 16},
{20, 19},
{21, 26},
{22, 23},
{23, 25},
{24, 21},
{16, 29},
{15, 28},
{20, 27},
{19, 30},
{25, 24},
{26, 22},
{25, 26},
{27, 23},
{28, 22},
{27, 28},
{29, 21},
{30, 24},
{29, 30},
{31, 17},
{32, 18},
{33, 35},
{34, 32},
{35, 16},
{36, 40},
{36, 37},
{37, 39},
{38, 12},
{38, 39},
{40, 44},
{41, 38},
{37, 42},
{41, 43},
{42, 40},
{43, 39},
{42, 45},
{44, 48},
{45, 49},
{46, 41},
{47, 43},
{48, 46},
{49, 47},
{48, 49},
{44, 45},
{46, 47},
{51, 75},
{51, 57},
{52, 56},
{53, 54},
{54, 52},
{55, 53},
{56, 58},
{57, 55},
{58, 50},
{51, 60},
{59, 50},
{60, 59},
{61, 70},
{62, 63},
{63, 67},
{64, 61},
{50, 61},
{51, 62},
{60, 63},
{59, 64},
{65, 69},
{66, 68},
{67, 65},
{68, 62},
{69, 64},
{70, 66},
{67, 68},
{65, 66},
{69, 70},
{155, 73},
{71, 72},
{73, 72},
{74, 16},
{75, 74},
{74, 79},
{76, 78},
{77, 76},
{78, 75},
{79, 77},
{79, 78},
{2, 80},
{81, 3},
{134, 81},
{89, 82},
{85, 83},
{82, 84},
{83, 81},
{80, 82},
{71, 86},
{96, 87},
{87, 86},
{87, 89},
{93, 88},
{89, 90},
{91, 90},
{9, 91},
{90, 93},
{120, 93},
{92, 94},
{94, 91},
{98, 96},
{96, 95},
{83, 98},
{98, 97},
{80, 99},
{118, 99},
{117, 101},
{115, 102},
{104, 99},
{100, 103},
{103, 104},
{110, 105},
{107, 106},
{109, 107},
{105, 108},
{113, 100},
{112, 99},
{111, 104},
{114, 103},
{108, 109},
{106, 110},
{110, 109},
{107, 111},
{106, 112},
{112, 111},
{105, 113},
{108, 114},
{114, 113},
{101, 115},
{102, 116},
{119, 117},
{116, 118},
{100, 119},
{124, 120},
{121, 120},
{123, 121},
{94, 122},
{123, 122},
{128, 124},
{122, 125},
{126, 121},
{127, 125},
{124, 126},
{123, 127},
{129, 126},
{132, 128},
{133, 129},
{125, 130},
{127, 131},
{130, 132},
{131, 133},
{133, 132},
{129, 128},
{131, 130},
{159, 135},
{141, 135},
{140, 136},
{138, 137},
{136, 138},
{137, 139},
{142, 140},
{139, 141},
{134, 142},
{144, 135},
{134, 143},
{143, 144},
{154, 145},
{147, 146},
{151, 147},
{145, 148},
{145, 134},
{146, 135},
{147, 144},
{148, 143},
{153, 149},
{152, 150},
{149, 151},
{146, 152},
{148, 153},
{150, 154},
{152, 151},
{150, 149},
{154, 153},
{157, 155},
{156, 71},
{156, 157},
{100, 158},
{158, 159},
{163, 158},
{162, 160},
{160, 161},
{159, 162},
{161, 163},
{162, 163},
};
const Model _car_model = {_car_verts, 164, _car_edges, 227};


Компилятору надо скармливать только gdi_3d.cpp, он #include-ит models.cpp (который сгенерирован в результате экспорта из gmax ; могу написать как, если хотите). Так проще всего, чтобы не заморачиваться на чтение моделей из файла.

3D-отсечение (clipping) не делается, чтобы код был проще. То есть если ребро частично позади камеры, то оно отбрасывается целиком. 2D-отсечение делает GDI (рёбра не вылезают за пределы клиентской области окна).

Обработка ошибок отсутствует, чтобы код был проще. По-хорошему, надо проверять, успешно ли отработала WinAPI-шная функция (CreateCompatibleBitmap, например).

Я не заморачивался на exception safety, чтобы код был проще. Также, нельзя выпускать C++-исключение за пределы оконной процедуры (и вообще любого WinAPI-шного callback-а).

Код использует A-функции (например, CreateWindowEx A ), которые работают с текстом в ANSI-кодировке (если Windows настроена на русский язык, то ANSI-кодировка -- это code page 1251). Но сейчас лучше использовать W-функции (например, CreateWindowEx W ), которые работают с текстом в кодировке UTF-16. Именно эта кодировка является родной для современных Windows. Недостаток использования W-функций: программа не будет работать в Windows 9x (95/98/ME). (Этот недостаток можно устранить с помощью MSLU (Microsoft Layer for Unicode), но это уже другая история.)

Короче, это учебный пример, а не образец, как надо писать программы. Что непонятно -- спрашивайте, постараюсь ответить. Результат:
...
Рейтинг: 0 / 0
24.01.2013, 18:01
    #38123653
RomanH
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
3D C# GDI
Пётр Седов,

Спасибо Вам огромное! То что нужно!
Начинаю Ваш пример портировать на C#!
Думаю если я разберусь с каждой строкой при переводе, ко мне придет понимание.
...
Рейтинг: 0 / 0
Форумы / Программирование [игнор отключен] [закрыт для гостей] / 3D C# GDI / 6 сообщений из 6, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]