Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   

Die mobilen Seiten von c++.de:
http://m.c-plusplus.de
Infos hier [BETA]

  
c++.de :: WinAPI ::  Effizient Bilddaten aus Resource laden     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
nwp3
Unregistrierter




Beitrag nwp3 Unregistrierter 23:53:40 26.06.2012   Titel:   Effizient Bilddaten aus Resource laden            Zitieren

Ich habe ein Bitmap als Resource und benötige die Rohdaten um diese in eine OpenGL-Textur zu kopieren. Im Moment mache ich folgendes:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
HBITMAP hbmp = (HBITMAP)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(MY_BITMAP_RESOURCE), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
BITMAP bmp;
GetObject(hbmp, sizeof bmp, &bmp);
COLORREF *buffer = new COLORREF [b.bmHeight * b.bmWidth];
HDC hdc = CreateCompatibleDC(0);
SelectObject(hdc, hbmp);
for (int x = 0; x < b.bmWidth; x++)
    for (int y = 0; y < b.bmHeight; y++)
        buffer[x+b.bmWidth*y] = GetPixel(hdc, x, bmp.bmHeight - y);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bmp.bmWidth, bmp.bmHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
DeleteDC(hdc);
DeleteObject(hbmp);
delete buffer;
...


So weit funktioniert auch alles. Es sieht nur schrecklich ineffizient aus, Devices zu erstellen (da LoadImage ein DeviceIndependentBitmap erstellt und es unnötig ist) und alle Texturen Pixel für Pixel zu kopieren. Mit GetDIBits hatte ich keinen Erfolg wegen der Parameter (was sind Scanlines?) und auch sonst scheint es kein GetAllPixels(hdc, buffer) zu geben.
Weiß jemand wie es richtig geht?
knivil
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.02.2009
Beiträge: 5854
Beitrag knivil Mitglied 00:20:57 27.06.2012   Titel:              Zitieren

Du machst es doch nur einmal beim Start der Anwendung, wen kuemmert es, wie lange das dauert.

Zu deinem eigentlichen Problem: Keine Ahnung!

_________________
If it were not for laughter, there would be no Tao.
Sie können einen Beitrag nicht so schnell nach Ihrem letzten absenden, bitte warten Sie einen Augenblick.
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 16043
Beitrag hustbaer Mitglied 00:44:16 27.06.2012   Titel:              Zitieren

knivil schrieb:
Du machst es doch nur einmal beim Start der Anwendung, wen kuemmert es, wie lange das dauert.

Du hast dir den Code nichtmal angesehen, oder? :rolleyes:

Texturdaten pixelweise mit GetPixel() kopieren, ja, klar, muss man so machen.
Weil's ja so lustig ist ne Minute zu warten wo es 1-2 Sekunden auch tun würden.

_________________
"Let there be Licht..." http://lichttools.sourceforge.net/
Sehr cooles ASCII Spiel (leider nicht von mir): ASCII-Scramble - http://www.roskakori.at/ascii/
dot
Mitglied

Benutzerprofil
Anmeldungsdatum: 20.05.2004
Beiträge: 5618
Beitrag dot Mitglied 01:13:42 27.06.2012   Titel:              Zitieren

"Richtig": FindResource(), LoadResource() und LockResource() und dann die Bitmap einlesen...

_________________
one point of view will never reveal the entire scene.
knivil
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.02.2009
Beiträge: 5854
Beitrag knivil Mitglied 01:24:45 27.06.2012   Titel:              Zitieren

Zitat:
Du hast dir den Code nichtmal angesehen, oder?
Doch, aber ich habe nicht keine Vorstellung, wie lange die einzelnen Funktionsaufrufe benoetigen.

_________________
If it were not for laughter, there would be no Tao.
Sie können einen Beitrag nicht so schnell nach Ihrem letzten absenden, bitte warten Sie einen Augenblick.
dot
Mitglied

Benutzerprofil
Anmeldungsdatum: 20.05.2004
Beiträge: 5618
Beitrag dot Mitglied 01:28:54 27.06.2012   Titel:              Zitieren

knivil schrieb:
Zitat:
Du hast dir den Code nichtmal angesehen, oder?
Doch, aber ich habe nicht keine Vorstellung, wie lange die einzelnen Funktionsaufrufe benoetigen.

Ok, in dem Fall: GetPixel() ist so ziemlich die langsamste Lösung, die du in der kompletten Win32 API finden wirst. Wenn du nur schnell die Farbe unterm Mauszeiger haben willst, dann geht's grad, aber zum "Einlesen" eines ganzen Bildes ist GetPixel() völlig unbrauchbar... ;)

Das is wie einen Lastwagen voller Erde bestellen und die Erde dann mit einer Pinzette abladen, statt einfach runterzukippen...

_________________
one point of view will never reveal the entire scene.


Zuletzt bearbeitet von dot am 01:30:54 27.06.2012, insgesamt 1-mal bearbeitet
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 16043
Beitrag hustbaer Mitglied 01:30:49 27.06.2012   Titel:              Zitieren

@dot
Ich glaube beim "die Bitmap einlesen" hat er Probleme, deswegen will er ja LoadImage() verwenden.
Ich hab' mit WinAPI und DIBs auch schon zu lange nix mehr gemacht, deswegen bin ich da auch nimmer so fit.
Eine Möglichkeit wäre vermutlich die "von Hand" rauszukopieren.


@nwp3
Wenn die Bitmap 24 Bit ist, dann ist das auch relativ einfach. In dem Fall zeigt BITMAP::bmBits auf ein Array aus "Scanlines". Jede Scanlines representiert eine Zeile im Bild und ist BITMAP::bmWidthBytes lang. BITMAP::bmWidthBytes ist dabei grösser oder gleich BITMAP::bmWidth * 3.
Die Pixel in einer Zeile liegen direkt hintereinander, jeweils 3 Byte pro Pixel (je ein Byte für Rot, Grün, Blau). Die Reihenfolge der Bytes weiss ich nimmer, entweder Rot, Grün, Blau oder Blau, Grün, Rot, das merk' ich mir nie. Einfach ausprobieren.

Sonst könntest du noch eine andere Library verwenden um die Bilder zu laden, das hätte dann auch den Vorteil dass du nicht auf BMP beschränkt bist sondern PNG, JPEG etc. verwenden kannst. Zur Auswahl stehen viele - GDI+, FreeImage, CImg, CxImage, OpenIL (aka DevIL) und noch viele mehr die mir nicht einfallen bzw. die ich nicht kenne.

Konkret abraten würde ich nur von OpenIL, da das Ding im Zusammenhang mit Multithreading problematisch ist.

GDI+ hätte den Vorteil dass es mit Windows mitkommt, d.h. man muss nix extra einbinden (Header Files sind Teil des DSK und die DLLs werden mit Windows mit installiert). Wenn dein Projekt erstmal sowieso nur für Windows gemacht wird würde ich also GDI+ empfehlen. Ist auch halbwegs angenehm in der Anwendung.

_________________
"Let there be Licht..." http://lichttools.sourceforge.net/
Sehr cooles ASCII Spiel (leider nicht von mir): ASCII-Scramble - http://www.roskakori.at/ascii/


Zuletzt bearbeitet von hustbaer am 02:44:54 27.06.2012, insgesamt 1-mal bearbeitet
dot
Mitglied

Benutzerprofil
Anmeldungsdatum: 20.05.2004
Beiträge: 5618
Beitrag dot Mitglied 01:34:28 27.06.2012   Titel:              Zitieren

hustbaer schrieb:
@dot
Ich glaube beim "die Bitmap einlesen" hat er Probleme, deswegen will er ja LoadImage() verwenden.

Ja, das glaub ich auch. In dem Fall sollte er sich aber einfach anschauen, wie das geht. Es ist nicht besonders schwer und dabei auch mehr oder weniger die maximal effiziente Lösung, da die Resource im Prinzip ein memory mapped File ist und man im Idealfall den über LockResource() gefundenen Pointer praktisch direkt an glTexImage2D() weiterreichen kann (glPixelStore() macht's möglich)...



EDIT: Die moderne built-in Lösung für alle möglichen Bildformate unter Windows wäre btw WIC.

Random Code Snippet, weil ichs grad rumliegen hab (ist zwar für D3D11, aber ich denk man kann damit was anfangen; Resource::Blob ist im Prinzip ein Wrapper um den ganzen LockResource() Kram; Wenn man mehrere Bilder laden will, sollte man die Factory und den FormatConverter etc. natürlich dazwischen aufheben):
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
#include <Shlwapi.h>
#include <wincodec.h>
 
// ...
 
  com_ptr<ID3D11Texture2D> TextureAtlas::createAtlasTexture(ID3D11Device* device, const char* filename, size2ui& size)
  {
    Resource::Blob blob(filename, "IMAGE");
 
    com_ptr<IStream> stream = SHCreateMemStream(reinterpret_cast<const BYTE*>(blob.get()), blob.size());
    if (!stream)
      throw std::runtime_error("unable to create resource stream");
 
    com_ptr<IWICImagingFactory> factory;
    if (FAILED(CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<void**>(&factory))))
      throw std::runtime_error("unable to create WIC factory");
 
    com_ptr<IWICBitmapDecoder> decoder;
    if (FAILED(factory->CreateDecoderFromStream(stream, nullptr, WICDecodeMetadataCacheOnDemand, &decoder)))
      throw std::runtime_error("error creating image decoder");
 
    com_ptr<IWICBitmapFrameDecode> frame;
    if (FAILED(decoder->GetFrame(0, &frame)))
      throw std::runtime_error("unable to decode image");
 
    com_ptr<IWICFormatConverter> format_converter;
    if (FAILED(factory->CreateFormatConverter(&format_converter)))
      throw std::runtime_error("unable to create format converter");
 
    if (FAILED(format_converter->Initialize(frame, GUID_WICPixelFormat32bppRGBA, WICBitmapDitherTypeNone, nullptr, 0.0, WICBitmapPaletteTypeCustom)))
      throw std::runtime_error("unable to convert pixel format");
 
    if (FAILED(format_converter->GetSize(&size.width, &size.height)))
      throw std::runtime_error("unable to determine image size");
 
    D3D11_TEXTURE2D_DESC atlas_desc;
    atlas_desc.Width = size.width;
    atlas_desc.Height = size.height;
    atlas_desc.MipLevels = 1;
    atlas_desc.ArraySize = 1;
    atlas_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    atlas_desc.SampleDesc.Count = 1;
    atlas_desc.SampleDesc.Quality = 0;
    atlas_desc.Usage = D3D11_USAGE_DEFAULT;
    atlas_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    atlas_desc.CPUAccessFlags = 0;
    atlas_desc.MiscFlags = 0;
 
    std::unique_ptr<BYTE[]> buffer(new BYTE[size.width * size.height * 4]);
    if (FAILED(format_converter->CopyPixels(nullptr, size.width * 4, size.width * size.height * 4, buffer.get())))
      throw std::runtime_error("unable to read pixel data");
 
    D3D11_SUBRESOURCE_DATA data;
    data.pSysMem = buffer.get();
    data.SysMemPitch = size.width * 4;
 
    com_ptr<ID3D11Texture2D> atlas_tex;
    if (FAILED(device->CreateTexture2D(&atlas_desc, &data,  &atlas_tex)))
      throw std::runtime_error("unable to create atlas texture");
 
    return atlas_tex;
  }

_________________
one point of view will never reveal the entire scene.


Zuletzt bearbeitet von dot am 01:59:26 27.06.2012, insgesamt 11-mal bearbeitet
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 16043
Beitrag hustbaer Mitglied 02:41:48 27.06.2012   Titel:              Zitieren

dot schrieb:
... im Idealfall den über LockResource() gefundenen Pointer praktisch direkt an glTexImage2D() weiterreichen kann (glPixelStore() macht's möglich)...

Kann man den GL_UNPACK_ALIGNMENT Wert verwenden damit OpenGL das 4-Byte Row-Alignment von BMP Files "versteht"?
Das ginge dann ja noch.

Was ich aber nicht verstehe, ist, warum es da keinen GL_UNPACK_BYTES_PER_ROW Wert gibt. (Bzw. wieso GL_UNPACK_ROW_LENGTH nicht einfach in Bytes ist)
So ziemlich alle Image-Libraries die ich kenne haben einen "bytes per line" Wert im Interface. D.h. in dem Fall müsste man erst wieder in einen Zwischenpuffer kopieren, oder übersehe ich was?

_________________
"Let there be Licht..." http://lichttools.sourceforge.net/
Sehr cooles ASCII Spiel (leider nicht von mir): ASCII-Scramble - http://www.roskakori.at/ascii/


Zuletzt bearbeitet von hustbaer am 02:47:15 27.06.2012, insgesamt 1-mal bearbeitet
c++.de :: WinAPI ::  Effizient Bilddaten aus Resource laden   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.