Форум программистов, компьютерный форум, киберфорум
C++: WinAPI
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/15: Рейтинг темы: голосов - 15, средняя оценка - 5.00
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
1

Create an in memory bitmap and draw directly to the memory

11.12.2014, 19:33. Просмотров 3024. Ответов 10
Метки нет (Все метки)


Здравствуйте! У меня есть пара вопросов. Знаю, что рисовать в HDC можно только с одного потока. Но узнал такую вещь, что можно создать bitmap и получить указатель на его данные (предполагаю двумерный массив). Мне это нужно для того чтобы рисовать прямо в эту память используя несколько потоков.

Вопрос первый: Обязательно ли нужно создавать bitmap через функцию CreateDIBitmap или можно его создать через CreateCompatibleBitmap (для того чтобы иметь возможность получить указатель на его данные)?

Вопрос второй: Как вообще получить этот указатель? Узнал, что можно "запереть" bitmap for write access.

Если можно, то скиньте пожаолуйста небольшой образец, в котором можно будет указать цвет пикселя bitmap используя указатель на его данные. Заранее спасибо!
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.12.2014, 19:33
Ответы с готовыми решениями:

Out of memory
прога использует AlphaControls. при линковке выпадает оут оф мемори.

Out of memory
Приветствую уважаемые! Изучаю ассемблер по учебнику "Ассемблер - это просто". Дошел до создания...

Out of memory
После добавления очередной формы в проект при попытке его сохранить возникает ошибка Out Of Memory...

Out of memory
Недавно решил освоить графику в с++, и при прорисовке изображения на канве заметил, что оно...

__________________
Помогаю в написании студенческих работ здесь.
Записывайтесь на профессиональные курсы C++ разработчиков
10
565 / 194 / 70
Регистрация: 25.05.2012
Сообщений: 806
13.12.2014, 16:50 2
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Знаю, что рисовать в HDC можно только с одного потока.
На чем основывается это утверждение? Кто запретил рисовать из разных потоков?
0
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
14.12.2014, 18:58  [ТС] 3
Это находится в WM_PAINT:
C++
1
2
3
4
5
6
7
8
9
for (int i = 0; i < dc_array.size(); i++)
{
    func_threads.at(i) = thread(anyFunс2, dc_array[i], i);
}   
 
for (unsigned i = 0; i < func_threads.size(); i++)
{
    if (func_threads[i].joinable()) func_threads[i].join();
}
А вот сама функция anyFunc2:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void anyFunс2(HDC dc, int index)
{
    POINT points[3];
 
    for (unsigned i = index; i < model->vertexFaces.size(); i += fs)
    {
        // Here we convert our points to Clip and Windowed Coordinates
        // and only then fetch the results
        if (i < model->vertexFaces.size() && Algorithms::FetchPolygons(&model->finalizedVertices[0], model->vertexFaces[i], points))
        {
            Polygon(dc, points, 3);
        }
    }
}
Рисует только один из потоков. Вот тут мне сказали, что GDI не разработан таким образом, чтобы поддерживать многопотончое рисование на один DC. Мой друг (Luke Thatcher) также сказал следующее:
The first thing is that, in Win32, all UI related operations can only be done on the thread which created the window
Если есть способ рисования на один DC различными потоками в одно и тоже время, то подскажите как это сделать. Сейчас я изучаю вот эти статейки: 1, 2, 3, 4
0
565 / 194 / 70
Регистрация: 25.05.2012
Сообщений: 806
14.12.2014, 19:28 4
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Если есть способ рисования на один DC различными потоками в одно и тоже время, то подскажите как это сделать.
Рисуете из нескольких потоков в один DC и все. Единственный момент, нужно правильно засинхронизировать эти потоки, чтобы контекст устройства не использовался одновременно несколькими потоками. И это стандартная задача при работе с потоками, для синхронизации есть множество средств, в качестве варианта - критические секции.
0
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
14.12.2014, 20:12  [ТС] 5
Цитата Сообщение от dmitry94 Посмотреть сообщение
...контекст устройства не использовался одновременно несколькими потоками
Так в этом то и проблема: зачем мне многопоточность, если контекст устройство не может использоаться одновременно несколькими потоками? Допустим мне надо нарисовать 8 треугольников. Я могу создать 8 потоков (грубо говоря) и хотелось бы нарисовать 8 треугольников параллельно. Если другим потокам придётся ждать заверщения предыдущих потоков, то рисоание треугольников будет происходить последовательно.
0
565 / 194 / 70
Регистрация: 25.05.2012
Сообщений: 806
14.12.2014, 20:44 6
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Если другим потокам придётся ждать заверщения предыдущих потоков
Не нужно ждать завершения потоков, нужно ждать пока завершится обращение к DC.
С этим же вы столкнетесь при обращении к любому общему ресурсу на запись, не только к DC.
0
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
15.12.2014, 01:49  [ТС] 7
Ёмаё, да в моём потоке только обращение к дц и происходит... Печалька, блин.
0
565 / 194 / 70
Регистрация: 25.05.2012
Сообщений: 806
15.12.2014, 05:40 8
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Ёмаё, да в моём потоке только обращение к дц и происходит... Печалька, блин.
Идея следующая: Создать для каждого потока отдельное DC, рисовать туда сколько угодно параллельно, затем копировать на экран.

Добавлено через 2 часа 14 минут
CreateCompatibleDC
CreateCompatibleBitmap
BitBlt
0
35 / 17 / 10
Регистрация: 13.12.2014
Сообщений: 107
15.12.2014, 14:31 9
Pro100Tom, Я делаю так:
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
RECT gclientrect;
HDC gnewdc;
HBITMAP gnewbitmap;
int* gpnewbitmap;
 
void ResizeBitmap()
{
    if ((gnewdc != NULL) && (gclientrect.right != 0) && (gclientrect.bottom != 0))
    {
        BITMAPINFO lbitmapinfo;
        lbitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        lbitmapinfo.bmiHeader.biWidth = gclientrect.right;
        lbitmapinfo.bmiHeader.biHeight = -gclientrect.bottom;
        lbitmapinfo.bmiHeader.biPlanes = 1;
        lbitmapinfo.bmiHeader.biBitCount = 32;
        lbitmapinfo.bmiHeader.biCompression = BI_RGB;
        lbitmapinfo.bmiHeader.biSizeImage = gclientrect.right * gclientrect.bottom * 4;
        lbitmapinfo.bmiHeader.biClrUsed = 0;
        lbitmapinfo.bmiHeader.biClrImportant = 0;
        if (gnewbitmap != NULL) DeleteObject(gnewbitmap);
        gnewbitmap = CreateDIBSection(gnewdc, &lbitmapinfo, DIB_RGB_COLORS, (void**)&gpnewbitmap, NULL, NULL);
        SelectObject(gnewdc, gnewbitmap);
    };
};
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
 
    switch (message) 
    {
    case WM_SIZE:
        {
            GetClientRect(hWnd, &gclientrect);
            ResizeBitmap();
            break;
        };
    case WM_CREATE:
        {
            if (gnewdc == NULL)
            {
                HDC lhdc = GetDC(hWnd);
                gnewdc = CreateCompatibleDC(lhdc);
                ReleaseDC(hWnd, lhdc);
            };
            break;
        };
    case WM_ERASEBKGND:
        return 1;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
 
        if (gnewdc == NULL) gnewdc = CreateCompatibleDC(hdc);
 
        BitBlt(hdc,0,0,gclientrect.right,gclientrect.bottom,gnewdc,0,0,SRCCOPY);
        // TODO: Add any drawing code here...
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
то есть создаю совместимый контекст, создаю битмап с помощью CreateDIBSection, далее можно работать с массивом пикселей через указатель gpnewbitmap. А по сообщению WM_PAINT копирую из своего DC в DC окна.
Способа как обращаться напрямую к пикселям окна через GDI не знаю. Но знаю что такая возможность есть в DirectX. Но даже там я не писал напрямую в окно, а использовал двойную буферизацию. То есть пока в окне отображается один фрейм происходит отрисовка следующего фрейма, по окончании отрисовки происходит переключение: новый фрейм в окно, на старом происходит новая отрисовка. Иначе, если писать напрямую в окно появляется мерцание (видно как происходит заливка и отрисовка).
1
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
15.12.2014, 23:01  [ТС] 10
Цитата Сообщение от dmitry94 Посмотреть сообщение
Идея следующая: Создать для каждого потока отдельное DC, рисовать туда сколько угодно параллельно, затем копировать на экран.
Делал так, не прокатывает. Пробовал все различные флаги (SRCCOPY, SRCPAINT, SRCERASE, SRCINVERSE) со всеми различными цветовыми комбинациями. Никак не удаётся отрисовать полигоны в нужном порядке.

Добавлено через 44 минуты
Спасибо большое за образец. Я обязательно протестирую это вариант и отпишусь. Правда недельку меня не будет.
0
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
30.12.2014, 01:03  [ТС] 11
Всё работает великолепно! Спасибо огронмное!
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.12.2014, 01:03

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.

Out of memory
Всем привет. У меня есть две матрицы размеров 306000 на 14000. Мне нужно поэлементно разделить их...

Out of memory
Не подскажите из-за чего здесь может возникать Out of memory? v2 и r2 - динамические массивы. ...

Out of memory
то ли я чего то не понимаю, то ли что... весит папка с приложением 4,1мб. собирается под...

Out of memory в C++ builder
Здравствуйте! Расскажите, пожалуйста, что надо делать в программе, чтобы избежать outofmemory...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.