Created
March 5, 2024 16:20
-
-
Save superwills/edfea86d5e8ccc19c5f40b71a52d747d to your computer and use it in GitHub Desktop.
OpenGL renderbuffer Render to texture
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _CRT_SECURE_NO_DEPRECATE | |
#include <windows.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
#define GLEW_STATIC | |
#include <GL/glew.h> | |
#include <gl/gl.h> | |
#include <gl/glu.h> | |
#include <map> | |
using std::map, std::make_pair; | |
#pragma comment(lib, "opengl32.lib") | |
#pragma comment(lib, "glu32.lib") | |
#pragma comment(lib, "glew32s.lib") | |
struct Globals { | |
HINSTANCE hInstance; | |
HWND hwnd; | |
HDC hdc; | |
HGLRC hglrc; | |
int width, height; | |
}; | |
Globals g; | |
// Function prototypes. | |
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ); | |
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow ); | |
void draw(); // drawing function containing OpenGL function calls | |
// GL ERR | |
map<int, const char *> createErrMap() { | |
map<int, const char *> errmap; | |
errmap.insert( make_pair( 0x0000, "GL_NO_ERROR" ) ); | |
errmap.insert( make_pair( 0x0500, "GL_INVALID_ENUM" ) ); | |
errmap.insert( make_pair( 0x0501, "GL_INVALID_VALUE" ) ); | |
errmap.insert( make_pair( 0x0502, "GL_INVALID_OPERATION" ) ); | |
errmap.insert( make_pair( 0x0503, "GL_STACKOVERFLOW" ) ); | |
errmap.insert( make_pair( 0x0504, "GL_STACK_UNDERFLOW" ) ); | |
errmap.insert( make_pair( 0x0505, "GL_OUTOFMEMORY" ) ); | |
errmap.insert( make_pair( 0x8CD5, "GL_FRAMEBUFFER_COMPLETE" ) ); | |
errmap.insert( make_pair( 0x8CD6, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT" ) ); | |
errmap.insert( make_pair( 0x8CD7, "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT" ) ); | |
errmap.insert( make_pair( 0x8CD9, "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS" ) ); | |
errmap.insert( make_pair( 0x8CDD, "GL_FRAMEBUFFER_UNSUPPORTED" ) ); | |
return errmap; | |
} | |
map<int, const char *> glErrName = createErrMap(); | |
bool GL_OK() { | |
GLenum err = glGetError(); | |
if( err != GL_NO_ERROR ) { | |
printf( "GLERROR %d %s", err, glErrName[ err ] ); | |
} | |
return err == GL_NO_ERROR; | |
} | |
bool GL_OK( int line, const char *file ) { | |
GLenum err = glGetError(); | |
if( err != GL_NO_ERROR ) { | |
printf( "GLERROR %d %s, line=%d of file=%s", err, glErrName[ err ], line, file ); | |
} | |
return err == GL_NO_ERROR; | |
} | |
#define CHECK_GL GL_OK( __LINE__, __FILE__ ) | |
GLuint fboId = 0, texId = 0, renderbufferDepthId = 0; | |
int texW = 1024, texH = 1024; | |
void initFramebuffer() { | |
glGenFramebuffers(1, &fboId); | |
glBindFramebuffer(GL_FRAMEBUFFER, fboId); | |
glGenTextures(1, &texId); | |
glBindTexture(GL_TEXTURE_2D, texId); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texW, texH, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0); | |
// Here's how you'd createa color render buffer that IS NOT bound to a texture. | |
//glGenRenderbuffers( 1, &renderBufferColorId ) ; | |
//glBindRenderbuffer( GL_RENDERBUFFER, renderBufferColorId ); | |
// Have OpenGL store the colorbuffer contents as an inaccessible renderbuffer | |
//glRenderbufferStorage( GL_RENDERBUFFER, GL_RGBA8, 16, 16 ) ; | |
//glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBufferColorId ); | |
// 3. depth | |
//glGenRenderbuffers(1, &renderbufferDepthId); | |
//glBindRenderbuffer(GL_RENDERBUFFER, renderbufferDepthId); | |
//glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, texW, texH); | |
//glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbufferDepthId); | |
glBindFramebuffer( GL_FRAMEBUFFER, 0 ); | |
} | |
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow ) { | |
g.hInstance = hInstance; | |
WNDCLASS wc; | |
wc.cbClsExtra = 0; | |
wc.cbWndExtra = 0; | |
wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH ); | |
wc.hCursor = LoadCursor( NULL, IDC_ARROW ); | |
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION ); | |
wc.hInstance = hInstance; | |
wc.lpfnWndProc = WndProc; | |
wc.lpszClassName = TEXT( "glWindow" ); | |
wc.lpszMenuName = 0; | |
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; | |
RegisterClass( &wc ); | |
RECT rect; | |
SetRect( &rect, 50, 50, 850, 650 ); | |
// Save width and height off. | |
g.width = rect.right - rect.left; | |
g.height = rect.bottom - rect.top; | |
// Adjust it. | |
AdjustWindowRect( &rect, WS_OVERLAPPEDWINDOW, false ); | |
g.hwnd = CreateWindow( TEXT( "glWindow" ), | |
TEXT( "GL WINDOW!" ), | |
WS_OVERLAPPEDWINDOW, | |
rect.left, rect.top, // adjusted x, y positions | |
rect.right - rect.left, rect.bottom - rect.top, // adjusted width and height | |
NULL, NULL, | |
hInstance, NULL ); | |
// check to see that the window | |
// was created successfully! | |
if( g.hwnd == NULL ) { | |
FatalAppExit( NULL, TEXT( "CreateWindow() failed!" ) ); | |
} | |
// and show. | |
ShowWindow( g.hwnd, iCmdShow ); | |
g.hdc = GetDC( g.hwnd ); | |
PIXELFORMATDESCRIPTOR pfd = { 0 }; | |
pfd.nSize = sizeof( PIXELFORMATDESCRIPTOR ); // just its size | |
pfd.nVersion = 1; // always 1 | |
pfd.dwFlags = PFD_SUPPORT_OPENGL | // OpenGL support - not DirectDraw | |
PFD_DOUBLEBUFFER | // double buffering support | |
PFD_DRAW_TO_WINDOW; // draw to the app window, not to a bitmap image | |
pfd.iPixelType = PFD_TYPE_RGBA; // red, green, blue, alpha for each pixel | |
pfd.cColorBits = 24; // 24 bit == 8 bits for red, 8 for green, 8 for blue. | |
// This count of color bits EXCLUDES alpha. | |
pfd.cDepthBits = 32; // 32 bits to measure pixel depth. That's accurate! | |
int chosenPixelFormat = ChoosePixelFormat( g.hdc, &pfd ); | |
if( chosenPixelFormat == 0 ) { | |
FatalAppExit( NULL, TEXT( "ChoosePixelFormat() failed!" ) ); | |
} | |
int result = SetPixelFormat( g.hdc, chosenPixelFormat, &pfd ); | |
if( result == NULL ) { | |
FatalAppExit( NULL, TEXT( "SetPixelFormat() failed!" ) ); | |
} | |
g.hglrc = wglCreateContext( g.hdc ); | |
wglMakeCurrent( g.hdc, g.hglrc ); | |
glewInit(); | |
glEnable( GL_TEXTURE_2D ); | |
initFramebuffer(); | |
MSG msg; | |
while( 1 ) { | |
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { | |
if( msg.message == WM_QUIT ) { | |
break; | |
} | |
TranslateMessage( &msg ); | |
DispatchMessage( &msg ); | |
} | |
else { | |
draw(); | |
} | |
} | |
wglMakeCurrent( NULL, NULL ); | |
wglDeleteContext( g.hglrc ); | |
ReleaseDC( g.hwnd, g.hdc ); | |
AnimateWindow( g.hwnd, 200, AW_HIDE | AW_BLEND ); | |
return msg.wParam; | |
} | |
void renderToTexture() { | |
// Set the rendering target to being our custom framebuffer | |
glBindFramebuffer( GL_FRAMEBUFFER, fboId ); | |
glViewport( 0, 0, texW, texH ); | |
glMatrixMode( GL_PROJECTION ); | |
glLoadIdentity(); | |
gluPerspective( 45.0, (float)g.width/g.height, 1, 1000 ); | |
glMatrixMode( GL_MODELVIEW ); | |
glLoadIdentity(); | |
gluLookAt( 0, 0, 10, | |
0, 0, 0, | |
0, 1, 0 ); | |
glClearColor( 0.5, 0.5, 0.5, 1 ); | |
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); | |
static float i = 0; | |
i += 0.001f; | |
float c = cosf( i ); | |
float s = sinf( i ); | |
glBegin( GL_TRIANGLES ); | |
glColor3f( c, 0, 0 ); | |
glVertex3f( 1 + c, 0 + s, 0 ); | |
glColor3f( c, s, 0 ); | |
glVertex3f( 0 + c, 1 + s, 0 ); | |
glColor3f( s, 0.1f, s ); | |
glVertex3f( -1 + c, 0 + s, 0 ); | |
glEnd(); | |
// Restore the default state: Bind to the default framebuffer again | |
glBindFramebuffer( GL_FRAMEBUFFER, 0 ); | |
} | |
void drawAxis(int axisLen) { | |
glLineWidth( 5.f ); | |
glBegin( GL_LINES ); | |
glColor3f( 1, 0, 0 ); | |
glVertex3f( 0, 0, 0 ); | |
glVertex3f( axisLen, 0, 0 ); | |
glColor3f( 0, 1, 0 ); | |
glVertex3f( 0, 0, 0 ); | |
glVertex3f( 0, axisLen, 0 ); | |
glColor3f( 0, 0, 1 ); | |
glVertex3f( 0, 0, 0 ); | |
glVertex3f( 0, 0, axisLen ); | |
glEnd(); | |
glLineWidth( 1.f ); | |
glBegin( GL_LINES ); | |
glColor3f( .7, 0, .7 ); | |
for( int x = 0; x < axisLen-1; x++ ) { | |
glVertex3f( x, 0, 0 ); | |
glVertex3f( x, 0, axisLen-1 ); | |
} | |
for( int z = 0; z < axisLen-1; z++ ) { | |
glVertex3f( 0, 0, z ); | |
glVertex3f( axisLen-1, 0, z ); | |
} | |
glEnd(); | |
} | |
void renderFromTexture() { | |
glViewport( 0, 0, g.width, g.height ); | |
glClearColor( 0.25, 0.25, 0.25, 1 ); | |
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); | |
glMatrixMode( GL_PROJECTION ); | |
glLoadIdentity(); | |
gluPerspective( 45.0, (float)g.width/g.height, 1, 1000 ); | |
glMatrixMode( GL_MODELVIEW ); | |
glLoadIdentity(); | |
gluLookAt( 10, 5, 25, | |
0, 0, 0, | |
0, 1, 0 ); | |
drawAxis(10); | |
// Draw from the texture that we drew to above | |
float qs = 10.f; | |
glBindTexture(GL_TEXTURE_2D, texId); | |
glBegin( GL_QUADS ); | |
glColor3f( 1, 1, 1 ); | |
glTexCoord2f( 0, 0 ); glVertex3f( 0, 0, 0 ); | |
glTexCoord2f( 1, 0 ); glVertex3f( qs, 0, 0 ); | |
glTexCoord2f( 1, 1 ); glVertex3f( qs, qs, 0 ); | |
glTexCoord2f( 0, 1 ); glVertex3f( 0, qs, 0 ); | |
glEnd(); | |
// Turn off the binding to that texture | |
glBindTexture(GL_TEXTURE_2D, 0); | |
} | |
void draw() { | |
renderToTexture(); | |
renderFromTexture(); | |
SwapBuffers( g.hdc ); | |
} | |
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) { | |
switch( message ) { | |
case WM_CREATE: | |
Beep( 50, 10 ); | |
return 0; | |
break; | |
case WM_PAINT: | |
{ | |
HDC hdc; | |
PAINTSTRUCT ps; | |
hdc = BeginPaint( hwnd, &ps ); | |
EndPaint( hwnd, &ps ); | |
} | |
return 0; | |
break; | |
case WM_KEYDOWN: | |
switch( wparam ) { | |
case VK_ESCAPE: | |
PostQuitMessage( 0 ); | |
break; | |
default: | |
break; | |
} | |
return 0; | |
case WM_DESTROY: | |
PostQuitMessage( 0 ); | |
return 0; | |
break; | |
} | |
return DefWindowProc( hwnd, message, wparam, lparam ); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment