Skip to content

Instantly share code, notes, and snippets.

@superwills
Created March 5, 2024 16:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save superwills/edfea86d5e8ccc19c5f40b71a52d747d to your computer and use it in GitHub Desktop.
Save superwills/edfea86d5e8ccc19c5f40b71a52d747d to your computer and use it in GitHub Desktop.
OpenGL renderbuffer Render to texture
#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