View Full Version : Grafica di base sotto windows
salve a tutti,
ho bisogno di un piccolo aiutino e spero che voi mi possiate aiutare.
Ho del mio vecchio codice dos che si occupava di rasterizzare poligoni
in 3d sullo schermo in modalità vesa in più risoluzioni, a 16 e 32 bpp.
Ora avrei bisogno di un porting quanto più diretto in windows.
Non mi serve la grafica accelerata in d3d o opengl, nè voglio usare librerie
particolari o peggio di terzi tipo sdl e simili; solo ciò che le librerie windows di
base (e sottolineo base) offrono per:
-inizializzare una finestra windowed o fullscreen
-accendere un pixel a 16 o 32 bit
-ottenere informazioni sullo stato corrente della finestra (bpp, windowed/fullscreen,
risoluzione corrente...) ad es. per aggiornare automaticamente in caso di resize della finestra
-utilizzare gli eventuali strumenti messi a disposizione per questa finestra tipo
double buffering (posso benissimo farlo io, ma se c'é già...)
-quanto altro mi possa servire vi venga in mente per questo lavoro
Prego chiunque possa darmi dei consigli o possa indirizzarmi verso qualche
link di scrivere due righe, mi servono solo le cose di base perché non ho molto
tempo.
Perdonatemi nel caso qualcuno abbia già postato domande del genere, ma mi
sembrava un po' complessa come domanda per una ricerca nel forum.
Grazie in anticipo!
salve a tutti,
ho bisogno di un piccolo aiutino e spero che voi mi possiate aiutare.
Ho del mio vecchio codice dos che si occupava di rasterizzare poligoni
in 3d sullo schermo in modalità vesa in più risoluzioni, a 16 e 32 bpp.
Ora avrei bisogno di un porting quanto più diretto in windows.
Non mi serve la grafica accelerata in d3d o opengl, nè voglio usare librerie
particolari o peggio di terzi tipo sdl e simili; solo ciò che le librerie windows di
base (e sottolineo base) offrono per:
-inizializzare una finestra windowed o fullscreen
-accendere un pixel a 16 o 32 bit
-ottenere informazioni sullo stato corrente della finestra (bpp, windowed/fullscreen,
risoluzione corrente...) ad es. per aggiornare automaticamente in caso di resize della finestra
-utilizzare gli eventuali strumenti messi a disposizione per questa finestra tipo
double buffering (posso benissimo farlo io, ma se c'é già...)
-quanto altro mi possa servire vi venga in mente per questo lavoro
Il problema principale è che la "filosofia" di gestione del video è profondamente diversa tra il vecchio DOS e Windows.
In Windows non hai l'accesso diretto alla memoria video. Se poi già dici che vuoi evitare direct-draw, direct-3d, opengl, e compagnia bella ... ti tranci via pure tutto quello che comunque ti avrebbe avvantaggiato e di molto!
Tu chiedi come inizializzare una finestra windowed o fullscreen.
Una finestra "classica" (con barra titolo, ecc...) ad aprirla non ci sono grossi problemi, il fatto è che non so cosa potresti ricavarci. In Windows la gestione dell'interfaccia grafica è fatta ad "eventi", non sei tu che decidi quando disegnare sulla finestra ma il sistema. Tu puoi solo rispondere agli eventi. In DOS invece si faceva quello che si voleva e quando si voleva, avevi il controllo completo di tutto.
In più in una finestra normale, puoi certamente disegnarci sopra ma non a basso livello. Accederci pixel per pixel mi sembra che sia possibile ma credo che sarebbe una palla ...
Dici anche una finestra fullscreen ... ma in modalità esclusiva o no??? Per avere la modalità esclusiva serve direct-draw, altrimenti fare una semplice finestra full-screen, torniamo al caso precedente.
Insomma fare un porting di un programma di grafica dal DOS al Windows la vedo dura senza utilizzare qualcosa che ti semplifica e velocizza la gestione della grafica!!
Perdona la mia ignoranza, ma non dovrebbe esserci comunque un sistema per
inizializzare e disegnare in una finestra senza utilizzare directdraw? io so di
qualcosa tipo wingdi o windib ora non ricordo che si occupa della grafica di
windows di base, nel senso ad es. che con visual studio non hai bisogno di
richiamare headers directx o opengl o sdl ma semplicemente le librerie di default
che escono con il compilatore fresco installato; qualcosa del genere dovrebbe
essere anche disponibile con il dev-c++, che è la piattaforma che alla fine
vorrei usare.
Perdona la mia ignoranza, ma non dovrebbe esserci comunque un sistema per
inizializzare e disegnare in una finestra senza utilizzare directdraw? io so di
qualcosa tipo wingdi o windib ora non ricordo che si occupa della grafica di
windows di base, nel senso ad es. che con visual studio non hai bisogno di
richiamare headers directx o opengl o sdl ma semplicemente le librerie di default
che escono con il compilatore fresco installato; qualcosa del genere dovrebbe
essere anche disponibile con il dev-c++, che è la piattaforma che alla fine
vorrei usare.Certamente, basta usare la libreria GDI.
Se vuoi posso anche postarti del codice per creare una semplice finestra vuota. Ma devi comunque capire la gestione degli eventi in Windows (se non la conosci già ovviamente).
Se vuoi posso anche postarti del codice per creare una semplice finestra vuota. Ma devi comunque capire la gestione degli eventi in Windows (se non la conosci già ovviamente).
Grazie!
Ogni aiuto sarà molto apprezzato.
Grazie!
Ogni aiuto sarà molto apprezzato.
Ti posto il codice sorgente per creare una semplice finestra vuota di 300x300 pixel.
#define STRICT
#include <windows.h>
#define MAIN_WNDCLASS "MiaClasseFinestra"
LRESULT CALLBACK Main_WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
return 0;
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint (hWnd, &ps);
EndPaint (hWnd, &ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage (0);
return 0;
case WM_CLOSE:
DestroyWindow (hWnd);
return 0;
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}
INT APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevious, LPSTR lpszCmdLine, INT iCmdShow)
{
WNDCLASSEX wcx;
HWND hWnd;
MSG msg;
wcx.cbSize = sizeof (wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = (WNDPROC) Main_WndProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;
wcx.hIcon = NULL;
wcx.hIconSm = NULL;
wcx.hCursor = LoadCursor (NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
wcx.lpszMenuName = NULL;
wcx.lpszClassName = MAIN_WNDCLASS;
if (!RegisterClassEx (&wcx))
{
MessageBox (NULL, "Errore nella registrazione della classe",
"ERRORE", MB_OK | MB_ICONEXCLAMATION);
return 1;
}
hWnd = CreateWindow (MAIN_WNDCLASS, "Titolo finestra", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 300, 300,
NULL, NULL, hInstance, NULL);
if (hWnd == NULL)
{
MessageBox (NULL, "Errore nella creazione della finestra",
"ERRORE", MB_OK | MB_ICONEXCLAMATION);
return 1;
}
ShowWindow (hWnd, SW_SHOWNORMAL);
UpdateWindow (hWnd);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return 0;
}Non so che compilatore usi o hai possibilità di usare, in ogni caso devi creare una applicazione Win32 di tipo GUI (non "console", per intenderci). Non hai bisogno di alcuna libreria, header o altra cosa particolare.
I passi per creare una semplice finestra sono:
- Creare una window-procedure, cioè la funzione che riceverà gli eventi relativi alla finestra (nel codice sopra è la funzione Main_WndProc).
- Creare una nuova classe di finestra (con RegisterClassEx).
- Creare una nuova finestra (con CreateWindow).
- Gestire il loop dei messaggi (con while (GetMessage .....ecc...).
Se c'è qualcosa che non ti è chiaro, chiedi pure. ;)
Ti ringrazio per tutto l'aiuto fornito (e per la pazienza!)
Appena ho un po' di tempo vedo di studiarmi qualche manuale di
programmazione in windows, credo proprio di averne bisogno. Comunque il
codice è abbastanza chiaro e qualche piccola(issima) applicazione windows
l'ho già fatta in passato quindi non dovrei avere grossi problemi a capire il
codice che mi hai gentilmente fornito.
Ciao e grazie ancora!
Ciao,
perdonate l'insistenza, volevo chiedere ancora qualcosa. Premesso che non ho avuto problemi con in codice di cui sopra, avrei ora bisogno di far convergere gli strumenti a disposizione con le mie esigenze. Non mi è necessario imparare per ora tutta l'architettura software di windows, solo alcuni metodi per ottenere strettamente ciò che al momento mi occorre.
A chiunque possa interessare, in pratica ho bisogno di mostrare un vecchio lavoro fatto anni fa per dos, su macchine moderne windows, che naturalmente non supportano più molte delle applicazioni grafiche dell'epoca. Mi è assolutamente indispensabile ridurre al minimo il numero di cambiamenti apportati al codice originale e utilizzare al minimo strumenti e librerie esterne.
Dunque, poniamoci nel caso che il mio programma disegni in un buffer in memoria un'immagine frutto di una elaborazione, come faccio a dire a windows di riversare il tutto nella finestra sullo schermo? (in maniera sufficientemente performante dato che si tratta di aggiornare svariate frame al secondo)?
Altra cosa: se ridimensiono al volo o massimizzo la finestra come ottengo la nuova risoluzione e come aggiorno con continuità l'output del programma su video?
Ringrazio anticipatamente e mi scuso per la (relativa) banalità delle mie domande (anche per quelle nuove che probabilmente farò in futuro).
Premesso che non ho avuto problemi con in codice di cui sopraBenissimo. A proposito, quale compilatore/ambiente stai usando?
avrei ora bisogno di far convergere gli strumenti a disposizione con le mie esigenze. Non mi è necessario imparare per ora tutta l'architettura software di windows, solo alcuni metodi per ottenere strettamente ciò che al momento mi occorre.
A chiunque possa interessare, in pratica ho bisogno di mostrare un vecchio lavoro fatto anni fa per dos, su macchine moderne windows, che naturalmente non supportano più molte delle applicazioni grafiche dell'epoca. Mi è assolutamente indispensabile ridurre al minimo il numero di cambiamenti apportati al codice originale e utilizzare al minimo strumenti e librerie esterne.Beh, questo ... dipende. Dipende molto da come è fatta l'applicazione DOS. Come ho già avuto modo di dire, il modo di gestione della grafica è molto differente tra DOS e Windows.
Dunque, poniamoci nel caso che il mio programma disegni in un buffer in memoria un'immagine frutto di una elaborazione, come faccio a dire a windows di riversare il tutto nella finestra sullo schermo? (in maniera sufficientemente performante dato che si tratta di aggiornare svariate frame al secondo)?Anche qui ... bisogna vedere come è fatto questo buffer. È un buffer "rettangolare"? Il pixel come sono rappresentati? a 8 bit? a 32 bit? In true-color?
Altra cosa: se ridimensiono al volo o massimizzo la finestra come ottengo la nuova risoluzione e come aggiorno con continuità l'output del programma su video?Nel codice che ho postato la finestra è "resizable" (ridimensionabile). Si può anche renderla non ridimensionabile, basta mettere al posto di WS_OVERLAPPEDWINDOW, i seguenti flag:
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
Se invece ti va bene una finestra ridimensionabile, ad ogni ridimensionamento, la window-procedure riceve il messaggio WM_SIZE, che "informa" della nuova dimensione.
Ringrazio anticipatamente e mi scuso per la (relativa) banalità delle mie domande (anche per quelle nuove che probabilmente farò in futuro).Nessun problema!
Innanzitutto grazie per la rapida risposta.
Cercherò sinteticamente di risolvere gli ultimi dettagli
Uso dev-c++ e visual studio, dipende dalla macchina sulla quale mi trovo.
Il mio programma è un semplice engine 3d; in sintesi carica un oggetto .3ds dal disco e lo renderizza sullo schermo in realtime ed io posso spostarlo e ruotarlo con la tastiera (anche con il mouse ma non è necessario per il momento...). Lavora in modalità vesa a 32 bit con le relative risoluzioni previste (640, 800...). Funziona sia in modalità double buffering (render in un buffer e riversamento nella mem video) che in page flipping (disegna in una zona della mem video mentre mostra l'altra, poi le scambia). A me basta il primo metodo, l'importante che vada abbastanza spedito...)
A me serve che il rispettivo programma windows faccia più o meno lo stesso, non è affatto necessario che rispetti le risoluzioni originali, basta che funzioni correttamente.
Grazie ancora per il tempo dedicatomi!
Piccolo aggiornamento:
ho trovato questo codice (http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=07) (vedere in fondo alla pagina per i sorgenti), peraltro molto chiaro e che compila su miriadi di piattaforme che fa in opengl esattamente ciò che io voglio fare in software.
In pratica è già tutto settato, solo che ad occuparsi del rendering è opengl. Non ne sono sicuro, ma forse se potessi accedere direttamente al buffer che poi viene swappato con SwapBuffers(hDC), dovrei semplicemente rimuovere ogni riferimento ad opengl e metterci poi il mio renderer. Sto trascurando qualcosa?
[...] Sto trascurando qualcosa? si: andresti a qualche fps di meno; ma giusto qualcuno... :rolleyes:
fidati, ti conviene usare OpenGL, se non addirittura Direct3D...
fidati, ti conviene usare OpenGL, se non addirittura Direct3D...o anche SDL, per esempio.
Ma da quello che ho capito, kekk0 non vuole usare librerie esterne.
fidati, ti conviene usare OpenGL, se non addirittura Direct3D...
Forse non sono molto bravo ad esprimermi, il fatto è che io ho bisogno usare proprio il mio renderer di triangoli in software. E' il fulcro dell' intera cosa. Vi pare che sia interessato semplicemente nel far girare un cubo al massimo dei fps? Era mia intenzione mostrare a delle persone la mia routine di rendering di triangoli, codice ed esecuzione. Comunque, fare questo (molto) minimal porting del mio programma in win forse non è così semplice quanto credevo. Mi scuso per il tempo che vi ho sottratto e vi ringrazio per l'aiuto disinteressato. Prima o poi dovrò comunque imparare :)
Forse non sono molto bravo ad esprimermi, il fatto è che io ho bisogno usare proprio il mio renderer di triangoli in software. E' il fulcro dell' intera cosa. Vi pare che sia interessato semplicemente nel far girare un cubo al massimo dei fps? Era mia intenzione mostrare a delle persone la mia routine di rendering di triangoli, codice ed esecuzione. Comunque, fare questo (molto) minimal porting del mio programma in win forse non è così semplice quanto credevo.Prima di "gettare la spugna", come si suol dire, potresti provare a dare una occhiata alla libreria SDL (www.libsdl.org (http://www.libsdl.org)).
Tu dici che hai già un tuo software che renderizza gli oggetti 3D, se ho capito bene, e quindi non hai bisogno di OpenGL, Direct-3D e simili (perché farebbero in sostanza la stessa cosa che hai già fatto tu).
Dal tuo software, sempre se ho capito bene, "esce" una mappa di pixel ed è quella che vorresti visualizzare direttamente in Windows.
Bene, la libreria SDL ti permette di "disegnare" su una superficie in modo abbastanza semplice, veloce e performante. Ecco cosa dice l'introduzione della SDL per il Video:
* Set a video mode at any depth (8-bpp or greater) with optional conversion, if the video mode is not supported by the hardware.
* Write directly to a linear graphics framebuffer.
* Create surfaces with colorkey or alpha blending attributes.
* Surface blits are automatically converted to the target format using optimized blitters and are hardware accelerated, when possible. MMX optimized blits are available for the x86.
* Hardware accelerated blit and fill operations are used if supported by the hardware.
Pensi che possa fare al caso tuo?
Mi scuso per il tempo che vi ho sottrattoFigurati. Non mi hai sottratto nulla. ;)
Forse non sono molto bravo ad esprimermi, il fatto è che io ho bisogno usare proprio il mio renderer di triangoli in software. E' il fulcro dell' intera cosa. Vi pare che sia interessato semplicemente nel far girare un cubo al massimo dei fps? Era mia intenzione mostrare a delle persone la mia routine di rendering di triangoli, codice ed esecuzione. Comunque, fare questo (molto) minimal porting del mio programma in win forse non è così semplice quanto credevo. Mi scuso per il tempo che vi ho sottratto e vi ringrazio per l'aiuto disinteressato. Prima o poi dovrò comunque imparare :) be', non si tratta di un programma molto sensato perché oggi quel tipo di lavoro lo fa l'hardware della scheda video, in maniera tale che nel frattempo la CPU può fare altroe il tutto si velocizza moltissimo; se così non fosse non esisterebbero tantissimi videogiochi 3D ma anche qualcuno 2D imho. esistono rari casi in cui software che renderizza manualmente (come il tuo) risulti più veloce (più fps) di software che si appoggia sull'hardware; si tratta di casi in cui i frame da renderizzare sono piuttosto semplici e la CPU è estremamente potente. normalmente l'uso di una GPU fa guadagnare tantissimo.
ad ogni modo credo che nella GDI quello che faccia di più al caso tuo siano le DIB Sections, ovvero bitmap di cui hai accesso diretto ai pixel di memoria (scordati SetPixel che è troppo lenta); trattandosi di bitmap ai quali hai accesso diretto però non possono essere selezionati in un DC associato ad una finestra (ottenuto cioè con GetDC): il DC deve essere per forza un Memory Device Context e lo puoi usare per realizzare il double buffering facendo periodicamente un BitBlt da questo Memory DC a quello della finestra.
recapitolando:
1) ti salvi in una variabile un handle al DC della tua finestra (GetDC)
2) crei un Memory DC (CreateCompatibleDC, e lo fai compatibile al display)
3) crei una DIB Section (CreateDIBSection)
4) selezioni la DIB Section nel Memory DC (SelectObject)
5) costruisci il tuo frame accedendo direttamente alla memoria della DIB Section, in cui troverai i pixels nel formato secondo il quale hai creato la DIB Section
6) quando hai costruito un frame fai BitBlt col Memory DC come sorgente e il DC della finestra come destinazione
inoltre ti consiglio di implementarlo con due thread in modo tale da sfruttare eventualmente le architetture multicore: il codice che costruisce i frames (cioè che fa il rendering vero e proprio) fallo in un thread a parte; tutto il resto nel thread primario.
Bene, la libreria SDL ti permette di "disegnare" su una superficie in modo abbastanza semplice, veloce e performante.
Lo so, ho già visto di cosa è capace SDL (vedi DOSBox), è davvero un bel progetto. Ma come già detto non posso usare librerie che non siano già incluse nel dev-c++ (in realtà dev include opengl ma comunque non devo usarlo).
be', non si tratta di un programma molto sensato perché oggi quel tipo di lavoro lo fa l'hardware della scheda video
Il senso di questo programma, se ancora non sono riuscito a spiegarlo, è mostrare il mio codice di rendering di triangoli in texture mapping in software, non dimostrare quanto sono bravo a chiamare le funzioni d3d o opengl. Sono nel settore dei pc da parecchio tempo ed ho programmato in una miriade linguaggi diversi, ho solo poca esperienza sotto piattaforme windows (lato programmazione), ma so perfettamente le capacità dell'hardware moderno.
Comunque ti ringrazio per le tue informazioni; cercherò di seguirle e di (finalmente) portare a termine questo progetto (tra l'altro lavorandoci 10 minuti al giorno causa lavoro...)
ciao a tutti!
ad ogni modo credo che nella GDI quello che faccia di più al caso tuo siano le DIB Sections, ovvero bitmap di cui hai accesso diretto ai pixel di memoria (scordati SetPixel che è troppo lenta); trattandosi di bitmap ai quali hai accesso diretto però non possono essere selezionati in un DC associato ad una finestra (ottenuto cioè con GetDC): il DC deve essere per forza un Memory Device Context e lo puoi usare per realizzare il double buffering facendo periodicamente un BitBlt da questo Memory DC a quello della finestra. recapitolando: 1) ti salvi in una variabile un handle al DC della tua finestra (GetDC) 2) crei un Memory DC (CreateCompatibleDC, e lo fai compatibile al display) 3) crei una DIB Section (CreateDIBSection) 4) selezioni la DIB Section nel Memory DC (SelectObject) 5) costruisci il tuo frame accedendo direttamente alla memoria della DIB Section, in cui troverai i pixels nel formato secondo il quale hai creato la DIB Section 6) quando hai costruito un frame fai BitBlt col Memory DC come sorgente e il DC della finestra come destinazione
@71104
non è che mi faresti un piccolo esempio di codice come ha fatto andrea?
non c'è fretta e se ti scocci non lo fare, non fa niente!
grazie in ogni caso!
non è
@71104
non è che mi faresti un piccolo esempio di codice come ha fatto andrea?
non c'è fretta e se ti scocci non lo fare, non fa niente!
grazie in ogni caso!
non è sottomano non ce l'ho, e da rifare sarebbe lungo e noioso (per esperienza i programmi Win32 non funzionano mai come vorresti alla prima botta, nonostante la loro semplicità :muro: ), comunque ti posso dire tutte le funzioni che devi usare (tutte documentate in MSDN):
- CreateCompatibleDC per creare un Memory DC
- GetDC per ottenere un handle a quello della tua finestra
- CreateDIBSection per creare un bitmap di cui hai un puntatore ai dati, che puoi modificare direttamente (occhio al formato)
- SelectObject per selezionare la DIB section nel Memory DC (quello creato con CreateCompatibleDC)
- BitBlt per copiare velocemente il contenuto di un DC a un altro; usala per copiare il contenuto della DIB section nel DC della finestra
- oppure in alternativa all'ultima, StretchBlt, che fa la stessa cosa ma con la possibilità di stretching dell'immagine (solo ortogonale però, niente deformazioni a trapezio)
spero di esserti stato utile, ciao.
grazie per la gentilezza, sei stato più che utile
ciao!
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.