#c #sdl #pixel #sdl-2
#c #sdl #пиксель #sdl-2
Вопрос:
Я работаю над функцией, которая «сопоставит» текстуру с целевой текстурой (где обе текстуры создаются с помощью подсказки SDL_TextureAccess «SDL_TEXTUREACCESS_STREAMING»). То есть, везде, где есть прозрачный пиксель (в частности, RGB все 255 и 0) на базовом изображении, соответствующий пиксель также будет сделан прозрачным на отображенном изображении. На изображении ниже показаны мои желаемые результаты (каждое изображение имеет размер 64×64 пикселя). Левая сторона без отображения.
Первоначально я сделал это, просто используя SDL_Textures, и код для этого можно найти ниже (проверка ошибок опущена для краткости):
void MapOntoTexture(SDL_Texture* base, SDL_Texture* mapped) { Uint32 base_format = 0; int height = 0; SDL_QueryTexture(base, amp;base_format, NULL, NULL, amp;height); SDL_PixelFormat* baseFormat = SDL_AllocFormat(base_format); Uint32 mapped_format = 0; int mappedHeight = 0; SDL_QueryTexture(mapped, amp;mapped_format, NULL, NULL, amp;mappedHeight); SDL_PixelFormat* mappedFormat = SDL_AllocFormat(mapped_format); void* basePixels = NULL; int basePitch = 0; SDL_LockTexture(base, NULL, amp;basePixels, amp;basePitch); Uint32* realBasePixels = basePixels; void* mappedPixels = NULL; int mappedPitch = 0; SDL_LockTexture(mapped, NULL, amp;mappedPixels, amp;mappedPitch); Uint32* realMappedPixels = mappedPixels; int basePixelsInt = (basePitch / 4) * height; int mappedPixelsInt = (mappedPitch / 4) * mappedHeight; Uint32 baseTransparent = SDL_MapRGBA(baseFormat, 0xFF, 0xFF, 0xFF, 0x00); Uint32 mappedTransparent = SDL_MapRGBA(mappedFormat, 0xFF, 0xFF, 0xFF, 0x00); for(int i = 0; i lt; basePixelsInt; i ) { if (realBasePixels[i] == baseTransparent) { realMappedPixels[i] = mappedTransparent; } } SDL_UnlockTexture(base); SDL_UnlockTexture(mapped); SDL_FreeFormat(baseFormat); SDL_FreeFormat(mappedFormat); }
Однако, перечитывая SDL-вики, я нашел эту цитату:
В качестве оптимизации пиксели, доступные для редактирования, не обязательно содержат старые данные текстуры. Это операция только для записи, и если вам нужно сохранить копию данных текстуры, вы должны сделать это на уровне приложения.
Часть, касающаяся только записи, касается меня, несмотря на то, что это работает в моей программе. Однако я подозреваю, что это случай неопределенного поведения демонов. Поэтому я написал другую функцию, которая вместо этого использует поверхности (а затем преобразует их в текстуры). Я признаю, что поверхности, возможно, потребуется заблокировать, и они указаны в фактическом коде, но опять же это опущено для краткости. Вот код:
void MapOntoSurface(SDL_Surface* base, SDL_Surface* mapped) { int basePixelsInt = (base-gt;pitch / 4) * base-gt;h; int mappedPixelsInt = (mapped-gt;pitch / 4) * mapped-gt;h; Uint32 baseTransparent = SDL_MapRGBA(base-gt;format, 0xFF, 0xFF, 0xFF, 0x00); Uint32 mappedTransparent = SDL_MapRGBA(mapped-gt;format, 0xFF, 0xFF, 0xFF, 0x00); Uint32* realBasePixels = base-gt;pixels; Uint32* realMappedPixels = mapped-gt;pixels; for(int i = 0; i lt; basePixelsInt; i ) { if (realBasePixels[i] == baseTransparent) { realMappedPixels[i] = mappedTransparent; } } //Use "mapped" surface to create texture later }
По общему признанию, это значительно проще, чем связанный с текстурой, но я бы предпочел этого не делать, так как это несколько неэлегантно, когда мне приходится преобразовывать поверхности в текстуры. Итак, наконец, мой вопрос: могу ли я использовать первую версию, не беспокоясь о неопределенном поведении, или мне следует использовать вторую?
Комментарии:
1. Как правило, в SDL операция записи на экран или текстуру является односторонней. Это означает, что вы генерируете пиксели, которые хотите записать, и выполняете запись (вывод на экран и т. Д.). Я так понимаю, это означает, что вы не можете ожидать, что будете считывать данные из области текстуры, которую вы изменили, чтобы восстановить те же данные. Таким образом, только запись и копирование на уровне приложения означает, что если вам нужно сохранить копию данных, которые вы собираетесь записать (для дальнейших изменений и т. Д.), Сделайте это, Не ожидайте, что вы прочитаете то, что вы написали для следующей модификации. (это мое «общее» понимание).
2. @David C. Рэнкин Итак, исходя из вашего понимания, вы бы сказали, что если бы я прочитал текстуру ровно один раз, то все было бы в порядке?
3. Насколько я понимаю, после записи в текстуру у вас нет гарантии, что вы сможете прочитать ту же информацию обратно. SDL может свободно обрабатывать память, связанную с текстурой, как скретч-панель после того, как сама текстура будет настроена для отображения. Вот почему у вас есть примечание о создании копии, если вам нужно сохранить то, что вы пишете. Я читал о
SDL_QueryTexture()
том, что он возвращает атрибуты текстуры, не обязательно каждого отдельного пикселя (это может быть, но не гарантировано-таким образом, копия). Я недостаточно занимаюсь SDL, чтобы быть авторитетом, но это мое прочтение записки.4. Правильно, вы не считываете данные текстуры обратно. Как я вижу, заблокированное содержимое буфера сохраняется только в реализации средства визуализации opengl, и даже там оно может пойти не так, если вы объедините его с
UpdateTexture
. Кроме того,LockTexture
используется только для потоковых текстур; все ли ваши текстуры помечены как потоковые? Если да, то понимаете ли вы, что это удваивает использование памяти в рендере opengl (единственном рендерере, кроме программного обеспечения, которое в настоящее время не удаляет заблокированные данные)? Это переназначение текстуры, которое вы делаете, — известно ли оно до программы lauch или динамично и может изменять каждый кадр?5. @keltar Все мои текстуры созданы с флагом потоковой передачи (см. Редактирование). Я не понимал, что это удваивает использование памяти, но только текстуры, которые должны использовать эту функцию, создаются с флагом потоковой передачи (только небольшое количество текстур должно использовать эту функцию). Переназначение текстур известно до запуска программы, но если бы я создал все текстуры до запуска, у меня осталось бы дополнительно ~25000 дополнительных изображений для моей игры. Это была не та стоимость, которую я хотел переложить на своего пользователя.