//
// This code was created by Lionel Brits / Jeff Molofee '99
//
// If you've found this code useful, please let me know.
//
// Visit NeHe Productions at www.demonews.com/hosted/nehe
//
/**************************************************************/
// This code was ported to MacOS by Tony Parker.
// I'd also appreciate it if you could drop me a line if you found
// this code useful.
//
// Tony Parker - asp#usc.edu
//
// Have a nice day.
#include <stdio.h> // Header File For Standard Input / Output
#include <stdarg.h> // Header File For Variable Argument Routines
#include <string.h> // Header File For String Management
#include <stdlib.h>
#include <stdbool.h>
#include <OpenGL/gl.h> // Header File For The OpenGL32 Library
#include <OpenGL/glu.h> // Header File For The GLu32 Library
#include <GLUT/glut.h> // Header File For The GLUT Library
#include "math.h"
#include "model.h"
// Constants ----------------------------------------------------------------------
#define kWindowHeight 400
#define kWindowWidth 400
// Structures ----------------------------------------------------------------
typedef struct // Create A Structure
{
GLubyte *imageData; // Image Data (Up To 32 Bits)
GLuint bpp; // Image Color Depth In Bits Per Pixel.
GLuint width; // Image Width
GLuint height; // Image Height
GLuint texID; // Texture ID Used To Select A Texture
} TextureImage; // Structure Name
// Function Prototypes -------------------------------------------------------
bool LoadTGA(TextureImage *texture, char *filename);
float rad(float angle);
void readstr(FILE *f,char *string);
void SetupWorld(void);
GLvoid InitGL(GLvoid);
GLvoid DrawGLScene(GLvoid);
GLvoid ReSizeGLScene(int Width, int Height);
GLvoid Idle(GLvoid);
GLvoid LoadGLTextures(void);
GLvoid Keyboard(unsigned char key, int x, int y);
// Global Variables ----------------------------------------------------------
char *worldfile = "world.txt";
bool light; // Lighting ON/OFF
bool gBlend; // Blending ON/OFF
GLfloat xrot; // X Rotation
GLfloat yrot; // Y Rotation
GLfloat xspeed; // X Rotation Speed
GLfloat yspeed; // Y Rotation Speed
GLfloat walkbias = 0;
GLfloat walkbiasangle = 0;
GLfloat lookupdown = 0.0f;
const float piover180 = 0.0174532925f;
float heading, xpos, zpos;
GLfloat camx=0, camy=0, camz=0; // Camera Location
GLfloat therotate;
GLfloat z=0.0f; // Depth Into The Screen
GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f }; // Ambient Light
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // Diffuse Light
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f, 1.0f }; // Light Position
GLuint filter; // Which Filter To Use
TextureImage texture[3]; // Storage for 3 textures
// Our Model Goes Here:
SECTOR sector1;
// rad -----------------------------------------------------------------------
// Converts Degrees To Radians. There Are 2 PI Radians In 360 Degrees.
float rad(float angle)
{
return angle * piover180;
}
// readstr -------------------------------------------------------------------
void readstr(FILE *f,char *string)
{
do
{
fgets(string, 255, f);
} while ((string[0] == '/') || (string[0] == '\n'));
return;
}
// SetupWorld ----------------------------------------------------------------
void SetupWorld(void)
{
float x, y, z, u, v;
int numtriangles;
FILE *filein;
char oneline[255];
filein = fopen(worldfile, "rt");
readstr(filein,oneline);
sscanf(oneline, "NUMPOLLIES %d\n", &numtriangles);
sector1.triangle = new TRIANGLE[numtriangles];
sector1.numtriangles = numtriangles;
int loop;
for ( loop = 0; loop < numtriangles; loop++)
{
int vert;
for ( vert = 0; vert < 3; vert++)
{
readstr(filein,oneline);
sscanf(oneline, "%f %f %f %f %f", &x, &y, &z, &u, &v);
sector1.triangle[loop].vertex[vert].x = x;
sector1.triangle[loop].vertex[vert].y = y;
sector1.triangle[loop].vertex[vert].z = z;
sector1.triangle[loop].vertex[vert].u = u;
sector1.triangle[loop].vertex[vert].v = v;
}
}
fclose(filein);
return;
}
#pragma mark -
// Main ----------------------------------------------------------------------
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(kWindowWidth, kWindowHeight);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
SetupWorld();
InitGL();
glutDisplayFunc(DrawGLScene);
glutReshapeFunc(ReSizeGLScene);
glutKeyboardFunc(Keyboard);
glutMainLoop();
return 0;
}
// InitGL ---------------------------------------------------------------------
GLvoid InitGL(GLvoid)
{
LoadGLTextures(); // Load The Texture ( ADD )
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping ( ADD )
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
gluPerspective(45.0f, (GLfloat) kWindowWidth / (GLfloat) kWindowHeight, 0.1f, 100.0f);
// Calculate The Aspect Ratio Of The Window
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
glEnable(GL_LIGHT1);
}
// Idle ---------------------------------------------------------------------
GLvoid Idle(GLvoid)
{
glutPostRedisplay();
}
// Keyboard -----------------------------------------------------------------
void Keyboard(unsigned char key, int x, int y)
{
#pragma unused (x, y)
switch(key)
{
case 'b': // turn blending on/off
gBlend = !gBlend;
if (!gBlend)
{
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
}
else
{
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
}
break;
case 'f':
filter+=1;
if (filter > 2)
{
filter = 0;
}
break;
case 'l':
light = !light;
if (!light)
glDisable(GL_LIGHTING);
else
glEnable(GL_LIGHTING);
break;
case 'w': // walk forward
xpos -= (float)sin(heading*piover180) * 0.05f;
zpos -= (float)cos(heading*piover180) * 0.05f;
if (walkbiasangle >= 359.0f)
walkbiasangle = 0.0f;
else
walkbiasangle+= 10;
walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
//lookupdown -= 1.0f;
break;
case 'x': // walk back
xpos += (float)sin(heading*piover180) * 0.05f;
zpos += (float)cos(heading*piover180) * 0.05f;
if (walkbiasangle <= 1.0f)
walkbiasangle = 359.0f;
else
walkbiasangle-= 10;
walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
//lookupdown += 1.0f;
break;
case 'd': // turn right
heading -= 1.0f;
yrot = heading;
break;
case 'a': // turn left
heading += 1.0f;
yrot = heading;
break;
case 'q':
z += 0.02f;
break;
case 'z':
z += 0.02f;
break;
default:
break;
}
glutPostRedisplay();
}
// DrawGLScene -------------------------------------------------------------
GLvoid DrawGLScene(GLvoid)
{
GLfloat x_m, y_m, z_m, u_m, v_m;
GLfloat xtrans, ztrans, ytrans;
GLfloat sceneroty;
xtrans = -xpos;
ztrans = -zpos;
ytrans = -walkbias-0.25f;
sceneroty = 360.0f- yrot;
int numtriangles;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glRotatef(lookupdown,1.0f,0,0);
glRotatef(sceneroty,0,1.0f,0);
glTranslatef(xtrans, ytrans, ztrans);
glBindTexture(GL_TEXTURE_2D, texture[filter].texID);
numtriangles = sector1.numtriangles;
// Process Each Triangle
int loop_m;
for ( loop_m = 0; loop_m < numtriangles; loop_m++)
{
glBegin(GL_TRIANGLES);
glNormal3f( 0.0f, 0.0f, 1.0f);
x_m = sector1.triangle[loop_m].vertex[0].x;
y_m = sector1.triangle[loop_m].vertex[0].y;
z_m = sector1.triangle[loop_m].vertex[0].z;
u_m = sector1.triangle[loop_m].vertex[0].u;
v_m = sector1.triangle[loop_m].vertex[0].v;
glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m);
x_m = sector1.triangle[loop_m].vertex[1].x;
y_m = sector1.triangle[loop_m].vertex[1].y;
z_m = sector1.triangle[loop_m].vertex[1].z;
u_m = sector1.triangle[loop_m].vertex[1].u;
v_m = sector1.triangle[loop_m].vertex[1].v;
glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m);
x_m = sector1.triangle[loop_m].vertex[2].x;
y_m = sector1.triangle[loop_m].vertex[2].y;
z_m = sector1.triangle[loop_m].vertex[2].z;
u_m = sector1.triangle[loop_m].vertex[2].u;
v_m = sector1.triangle[loop_m].vertex[2].v;
glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m);
glEnd();
}
glutSwapBuffers();
glFlush();
}
// ReSizeGLScene ------------------------------------------------------------
GLvoid ReSizeGLScene(int Width, int Height)
{
glViewport (0, 0, (GLsizei) Width, (GLsizei) Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (GLfloat) Width / (GLfloat) Height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// LoadGLTextures ------------------------------------------------------------
GLvoid LoadGLTextures(GLvoid)
{
//load texture
LoadTGA(&texture[0], "mud.tga");
LoadTGA(&texture[1], "mud.tga");
LoadTGA(&texture[2], "mud.tga");
// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[0].texID);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
//glTexImage2D(GL_TEXTURE_2D, 0, 3, texture1->sizeX, texture1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1->data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture[0].width, texture[0].height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture[0].imageData);
// Create Linear Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[1].texID);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
//glTexImage2D(GL_TEXTURE_2D, 0, 3, texture1->sizeX, texture1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1->data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture[1].width, texture[1].height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture[1].imageData);
// Create MipMapped Texture
glBindTexture(GL_TEXTURE_2D, texture[2].texID);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, texture[2].width, texture[2].height, GL_RGB, GL_UNSIGNED_BYTE, texture[2].imageData);
}
/********************> LoadTGA() <*****/
bool LoadTGA(TextureImage *texture, char *filename) // Loads A TGA File Into Memory
{
GLubyte TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0}; // Uncompressed TGA Header
GLubyte TGAcompare[12]; // Used To Compare TGA Header
GLubyte header[6]; // First 6 Useful Bytes From The Header
GLuint bytesPerPixel; // Holds Number Of Bytes Per Pixel Used In The TGA File
GLuint imageSize; // Used To Store The Image Size When Setting Aside Ram
GLuint temp; // Temporary Variable
GLuint type=GL_RGBA; // Set The Default GL Mode To RBGA (32 BPP)
FILE *file = fopen(filename, "rb"); // Open The TGA File
if( file==NULL || // Does File Even Exist?
fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare) || // Are There 12 Bytes To Read?
memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0 || // Does The Header Match What We Want?
fread(header,1,sizeof(header),file)!=sizeof(header)) // If So Read Next 6 Header Bytes
{
fclose(file); // If Anything Failed, Close The File
return false; // Return False
}
texture->width = header[1] * 256 + header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
texture->height = header[3] * 256 + header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
if( texture->width <=0 || // Is The Width Less Than Or Equal To Zero
texture->height <=0 || // Is The Height Less Than Or Equal To Zero
(header[4]!=24 && header[4]!=32)) // Is The TGA 24 or 32 Bit?
{
fclose(file); // If Anything Failed, Close The File
return false; // Return False
}
texture->bpp = header[4]; // Grab The TGA's Bits Per Pixel (24 or 32)
bytesPerPixel = texture->bpp/8; // Divide By 8 To Get The Bytes Per Pixel
imageSize = texture->width*texture->height*bytesPerPixel; // Calculate The Memory Required For The TGA Data
texture->imageData=(GLubyte *)malloc(imageSize); // Reserve Memory To Hold The TGA Data
if( texture->imageData==NULL || // Does The Storage Memory Exist?
fread(texture->imageData, 1, imageSize, file)!=imageSize) // Does The Image Size Match The Memory Reserved?
{
if(texture->imageData!=NULL) // Was Image Data Loaded
free(texture->imageData); // If So, Release The Image Data
fclose(file); // Close The File
return false; // Return False
}
GLuint i;
for( i=0; i<imageSize; i= i + bytesPerPixel) // Loop Through The Image Data
{ // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
temp=texture->imageData[i]; // Temporarily Store The Value At Image Data 'i'
texture->imageData[i] = texture->imageData[i + 2]; // Set The 1st Byte To The Value Of The 3rd Byte
texture->imageData[i + 2] = temp; // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
}
fclose (file); // Close The File
if (texture[0].bpp==24) // Was The TGA 24 Bits
{
type=GL_RGB; // If So Set The 'type' To GL_RGB
}
// Build A Texture From The Data
// We're doing this in a different function in this tutorial
glGenTextures(1, &texture[0].texID); // Generate OpenGL texture IDs
/*
glBindTexture(GL_TEXTURE_2D, texture[0].texID); // Bind Our Texture
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Linear Filtered
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtered
glTexImage2D(GL_TEXTURE_2D, 0, type, texture[0].width, texture[0].height, 0, type, GL_UNSIGNED_BYTE, texture[0].imageData);
*/
return true; // Texture Building Went Ok, Return True
}
NEED HELP.
I got this error:
/Users//Desktop/XcodeGLUT/../gora.cs.illinois.edu:display:cs418sp11:Home/Lesson
10 Folder/main.c:126:0
/Users//Desktop/XcodeGLUT/../gora.cs.illinois.edu:display:cs418sp11:Home/Lesson
10 Folder/main.c:126: error: 'new'
undeclared (first use in this
function)
rename the file to main.cpp, seems the file is compiled using the c-compiler and not the C++ compiler where new is a keyword for allocating on the heap (instead of malloc/calloc)
Related
I am trying to load gltf 2.0 models in openGl. For 1st model it is works fine. But for 2nd model, Model is loading well but have same texture as previous one. I don't know how to apply different textures on different models and changing position of one model changes position of all models same way. I searched much online but very few examples of loading gltf in openGL. They also not show how to load 2nd or 3rd gltf model in same project (screen).
My code is using libraries to load gltf and to compile shaders. That are few line of code libraries have simple openGl code for loading gltf and compiling shaders.
Main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
#define GL_SILENCE_DEPRECATION
#include <glad/glad.h> // Extend OpenGL Specfication to version 4.5 for WIN64 and versions 4.1 for Apple (note: two different files).
#include <imgui/imgui.h> // Load GUI library - Dear ImGui - https://github.com/ocornut/imgui
#include <imgui/imgui_impl_glfw.h> // Platform ImGui using GLFW
#include <imgui/imgui_impl_opengl3.h> // Platform new OpenGL - aka better than 3.3 core version.
#include <GLFW/glfw3.h> // Add GLFW - library to launch a window and callback mouse and keyboard - https://www.glfw.org
//#include <tinygltf/tiny_gltf.h> // Model loading library - tiny gltf - https://github.com/syoyo/tinygltf
//#include "src/stb_image.hpp" // Add library to load images for textures
#define GLM_ENABLE_EXPERIMENTAL // Enable all functions include non LTS
#include <glm/glm.hpp> // Add helper maths library - GLM 0.9.9.9 - https://github.com/g-truc/glm - for example variables vec3, mat and operators.
#include <glm/gtx/transform.hpp> // Help us with transforms
using namespace glm;
//#include "src/Mesh.hpp" // Simplest mesh holder and OBJ loader - can update more - from https://github.com/BennyQBD/ModernOpenGLTutorial
#include "src/Pipeline.hpp" // Setup pipeline and load shaders.
#include "src/Content.hpp" // Setup content loader and drawing functions - https://github.com/KhronosGroup/glTF - https://github.com/syoyo/tinygltf
#include "src/Debugger.hpp" // Setup debugger functions.
// Main fuctions
void startup();
void update();
void render();
void ui();
void endProgram();
// HELPER FUNCTIONS OPENGL
void hintsGLFW();
//string readShader(string name);
//void checkErrorShader(GLuint shader);
inline void errorCallbackGLFW(int error, const char *description){cout << "Error GLFW: " << description << "\n";};
void debugGL();
void APIENTRY openGLDebugCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar *message,
const GLvoid *userParam);
GLenum glCheckError_(const char *file, int line);
#define glCheckError() glCheckError_(__FILE__, __LINE__)
// Setup all the message loop callbacks - do this before Dear ImGui
// Callback functions for the window and interface devices
void onResizeCallback(GLFWwindow *window, int w, int h);
void onKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods);
void onMouseButtonCallback(GLFWwindow *window, int button, int action, int mods);
void onMouseMoveCallback(GLFWwindow *window, double x, double y);
void onMouseWheelCallback(GLFWwindow *window, double xoffset, double yoffset);
// VARIABLES
GLFWwindow *window; // Keep track of the window
auto windowWidth = 800; // Window width
auto windowHeight =800; // Window height
auto running(true); // Are we still running our main loop
mat4 projMatrix; // Our Projection Matrix
vec3 cameraPosition = vec3(0.0f, 0.0f, 5.0f); // Where is our camera
vec3 cameraFront = vec3(0.0f, 0.0f, -0.5f); // Camera front vector
vec3 cameraUp = vec3(0.0f, 1.0f, 0.0f); // Camera up vector
auto aspect = (float)windowWidth / (float)windowHeight; // Window aspect ration
auto fovy = 45.0f; // Field of view (y axis)
bool keyStatus[1024]; // Track key strokes
auto currentTime = 0.0f; // Framerate
auto deltaTime = 0.0f; // time passed
auto lastTime = 0.0f; // Used to calculate Frame rate
Pipeline pipeline; // Add one pipeline plus some shaders.
Pipeline pipelinelegs; // Add one pipeline plus some shaders.
Content content; // Add one content loader (+drawing).
Content contentlegs;
GLuint texture, texture2;
//Pipeline pipelineClegs; // Add one pipeline plus some shaders.
//Content contentClegs;
Debugger debugger; // Add one debugger to use for callbacks ( Win64 - openGLDebugCallback() ) or manual calls ( Apple - glCheckError() )
vec3 modelPosition; // Model position
vec3 modelRotation; // Model rotation
int main()
{
cout << endl << "===" << endl << "3D Graphics and Animation - Running..." << endl;
if (!glfwInit()) // Check if GLFW is working, if not then stop all
{
cout << "Could not initialise GLFW...";
return -1;
}
glfwSetErrorCallback(errorCallbackGLFW); // Setup a function callback to catch and display all GLFW errors.
hintsGLFW(); // Setup glfw with various hints.
const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); // Grab reference to monitor
// windowWidth = mode->width; windowHeight = mode->height; //fullscreen
// window = glfwCreateWindow(windowWidth, windowHeight, title.c_str(), glfwGetPrimaryMonitor(), NULL); // fullscreen
// Create our Window
const auto windowTitle = "My 3D Graphics and Animation OpenGL Application"s;
window = glfwCreateWindow(windowWidth, windowHeight, windowTitle.c_str(), NULL, NULL);
if (!window) // Test if Window or OpenGL context creation failed
{
cout << "Could not initialise GLFW...";
glfwTerminate();
return -1;
}
glfwSetWindowPos(window, 10, 10); // Place it in top corner for easy debugging.
glfwMakeContextCurrent(window); // making the OpenGL context current
// GLAD: Load OpenGL function pointers - aka update specs to newest versions - plus test for errors.
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD...";
glfwMakeContextCurrent(NULL);
glfwTerminate();
return -1;
}
glfwSetWindowSizeCallback(window, onResizeCallback); // Set callback for resize
glfwSetKeyCallback(window, onKeyCallback); // Set Callback for keys
glfwSetMouseButtonCallback(window, onMouseButtonCallback); // Set callback for mouse click
glfwSetCursorPosCallback(window, onMouseMoveCallback); // Set callback for mouse move
glfwSetScrollCallback(window, onMouseWheelCallback); // Set callback for mouse wheel.
// glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); // Set mouse cursor Fullscreen
// glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // Set mouse cursor FPS fullscreen.
// Setup Dear ImGui and add context - https://blog.conan.io/2019/06/26/An-introduction-to-the-Dear-ImGui-library.html
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO(); //(void)io;
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
ImGui::StyleColorsLight(); // ImGui::StyleColorsDark(); // Setup Dear ImGui style
// Setup Platform/Renderer ImGui backends
ImGui_ImplGlfw_InitForOpenGL(window, true);
const auto glsl_version = "#version 410";
ImGui_ImplOpenGL3_Init(glsl_version);
#if defined(__WIN64__)
debugGL(); // Setup callback to catch openGL errors. V4.2 or newer
#elif(__APPLE__)
glCheckError(); // Old way of checking for errors. Newest not implemented by Apple. Manually call function anywhere in code to check for errors.
#endif
glfwSwapInterval(1); // Ony render when synced (V SYNC) - https://www.tomsguide.com/features/what-is-vsync-and-should-you-turn-it-on-or-off
glfwWindowHint(GLFW_SAMPLES, 2); // Multisampling - covered in lectures - https://www.khronos.org/opengl/wiki/Multisampling
startup(); // Setup all necessary information for startup (aka. load texture, shaders, models, etc).
cout << endl << "Starting main loop and rendering..." << endl;
do{ // run until the window is closed
auto currentTime = (float)glfwGetTime(); // retrieve timelapse
deltaTime = currentTime - lastTime; // Calculate delta time
lastTime = currentTime; // Save for next frame calculations.
glfwPollEvents(); // poll callbacks
update(); // update (physics, animation, structures, etc)
render(); // call render function.
ui(); // call function to render ui.
#if defined(__APPLE__)
glCheckError(); // Manually checking for errors for MacOS, Windows has a callback.
#endif
glfwSwapBuffers(window); // swap buffers (avoid flickering and tearing)
running &= (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_RELEASE); // exit if escape key pressed
running &= (glfwWindowShouldClose(window) != GL_TRUE);
} while (running);
endProgram(); // Close and clean everything up...
// cout << "\nPress any key to continue...\n";
// cin.ignore(); cin.get(); // delay closing console to read debugging errors.
return 0;
}
void hintsGLFW(){
auto majorVersion = 3; auto minorVersion = 3; // define OpenGL version - at least 3.3 for bare basic NEW OpenGL
#if defined(__WIN64__)
majorVersion = 4; minorVersion = 5; // Recommended for Windows 4.5, but latest is 4.6 (not all drivers support 4.6 version).
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); // Create context in debug mode - for debug message callback
#elif(__APPLE__)
majorVersion = 4; minorVersion = 1; // Max support for OpenGL in MacOS
#endif
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // https://www.glfw.org/docs/3.3/window_guide.html
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, majorVersion);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minorVersion);
}
void endProgram()
{
// Clean ImGui
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwMakeContextCurrent(NULL); // destroys window handler
glfwTerminate(); // destroys all windows and releases resources.
}
void startup()
{
// string name = "assets/Fabric01_4K_BaseColor.png";
// int iWidth, iHeight, iChannels;
// unsigned char *iData = stbi_load(name.c_str(), &iWidth, &iHeight, &iChannels, 0);
// glGenTextures(1, &texture);
// //glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, texture);
// // glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, iWidth, iHeight);
// // glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, iWidth, iHeight, GL_RGB, GL_UNSIGNED_BYTE, iData);
// 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_REPEAT);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// if (iData)
// {
// glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
// glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
// glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iWidth, iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, iData);
// }else
// {
// std::cout << "Failed to load texture" << std::endl;
// }
// glGenerateMipmap(GL_TEXTURE_2D);
// stbi_image_free(iData);
// //glBindTexture(GL_TEXTURE_2D, 0);
// string namea = "assets/metal.png";
// int Width, Height, Channels;
// unsigned char *Data = stbi_load(namea.c_str(), &Width, &Height, &Channels, 0);
// glGenTextures(1, &texture2);
// glBindTexture(GL_TEXTURE_2D, texture2);
// 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_REPEAT);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// if (Data)
// {
// glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
// glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
// glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Data);
// }else
// {
// std::cout << "Failed to load texture" << std::endl;
// }
// glGenerateMipmap(GL_TEXTURE_2D);
// stbi_image_free(Data);
//glBindTexture(GL_TEXTURE_2D, 0);
cout << "VENDOR: " << (char *)glGetString(GL_VENDOR) << endl;
cout << "VERSION: " << (char *)glGetString(GL_VERSION) << endl;
cout << "RENDERER: " << (char *)glGetString(GL_RENDERER) << endl;
cout << endl << "Loading content..." << endl;
content.LoadGLTF("assets/Model.gltf");
content2.LoadGLTF("assets/Model2.gltf");
pipeline.CreatePipeline();
pipeline.LoadShaders("shaders/vs_model.glsl", "shaders/fs_model.glsl");
modelPosition = glm::vec3(0.0f, 0.0f, 0.0f);
modelRotation = glm::vec3(0.0f, 0.0f, 0.0f);
// A few optimizations.
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
// Get the correct size in pixels - E.g. if retina display or monitor scaling
glfwGetFramebufferSize(window, &windowWidth, &windowHeight);
// Calculate proj_matrix for the first time.
aspect = (float)windowWidth / (float)windowHeight;
projMatrix = glm::perspective(glm::radians(fovy), aspect, 0.1f, 1000.0f);
}
void update()
{
// modelRotation.y += 0.05f;
if (keyStatus[GLFW_KEY_LEFT]) modelRotation.y += 0.05f;
if (keyStatus[GLFW_KEY_RIGHT]) modelRotation.y -= 0.05f;
if (keyStatus[GLFW_KEY_UP]) modelRotation.x += 0.05f;
if (keyStatus[GLFW_KEY_DOWN]) modelRotation.x -= 0.05f;
if (keyStatus[GLFW_KEY_C] && keyStatus[GLFW_KEY_UP]) cameraPosition.y += 0.10f;
if (keyStatus[GLFW_KEY_C] && keyStatus[GLFW_KEY_DOWN]) cameraPosition.y -= 0.10f;
if (keyStatus[GLFW_KEY_C] && keyStatus[GLFW_KEY_RIGHT]) cameraPosition.x += 0.10f;
if (keyStatus[GLFW_KEY_C] && keyStatus[GLFW_KEY_LEFT]) cameraPosition.x -= 0.10f;
if (keyStatus[GLFW_KEY_C] && keyStatus[GLFW_KEY_I]) cameraPosition.z += 0.10f;
if (keyStatus[GLFW_KEY_C] && keyStatus[GLFW_KEY_O]) cameraPosition.z -= 0.10f;
if (keyStatus[GLFW_KEY_U] && keyStatus[GLFW_KEY_UP]) cameraUp.y += 0.10f;
if (keyStatus[GLFW_KEY_U] && keyStatus[GLFW_KEY_DOWN]) cameraUp.y -= 0.10f;
if (keyStatus[GLFW_KEY_U] && keyStatus[GLFW_KEY_RIGHT]) cameraUp.x += 0.10f;
if (keyStatus[GLFW_KEY_U] && keyStatus[GLFW_KEY_LEFT]) cameraUp.x -= 0.10f;
if (keyStatus[GLFW_KEY_U] && keyStatus[GLFW_KEY_I]) cameraUp.z += 0.10f;
if (keyStatus[GLFW_KEY_U] && keyStatus[GLFW_KEY_O]) cameraUp.z -= 0.10f;
if (keyStatus[GLFW_KEY_F] && keyStatus[GLFW_KEY_UP]) cameraFront.y += 0.10f;
if (keyStatus[GLFW_KEY_F] && keyStatus[GLFW_KEY_DOWN]) cameraFront.y -= 0.10f;
if (keyStatus[GLFW_KEY_F] && keyStatus[GLFW_KEY_RIGHT]) cameraFront.x += 0.10f;
if (keyStatus[GLFW_KEY_F] && keyStatus[GLFW_KEY_LEFT]) cameraFront.x -= 0.10f;
if (keyStatus[GLFW_KEY_F] && keyStatus[GLFW_KEY_I]) cameraFront.z += 0.10f;
if (keyStatus[GLFW_KEY_F] && keyStatus[GLFW_KEY_O]) cameraFront.z -= 0.10f;
if (keyStatus[GLFW_KEY_R]) pipeline.ReloadShaders();
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
void render()
{
glViewport(0, 0, windowWidth, windowHeight);
// Clear colour buffer
glm::vec4 inchyraBlue = glm::vec4(0.345f, 0.404f, 0.408f, 1.0f);
glm::vec4 backgroundColor = inchyraBlue;
glClearBufferfv(GL_COLOR, 0, &backgroundColor[0]);
// Clear deep buffer
static const GLfloat one = 1.0f;
glClearBufferfv(GL_DEPTH, 0, &one);
// Enable blend
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Use our shader programs
glUseProgram(pipeline.pipe.program);
//glUniform1i(glGetUniformLocation(pipeline.pipe.program, "texture1"), 0);
// Setup camera
glm::mat4 viewMatrix = glm::lookAt(cameraPosition, // eye
cameraPosition + cameraFront, // centre
cameraUp); // up
// Do some translations, rotations and scaling
// glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(modelPosition.x+rX, modelPosition.y+rY, modelPosition.z+rZ));
glm::mat4 modelMatrix = glm::translate(glm::mat4(5.0f), glm::vec3(0.0f, 0.4f, 0.0f));
modelMatrix = glm::rotate(modelMatrix, modelRotation.x, glm::vec3(1.0f, 0.0f, 0.0f));
modelMatrix = glm::rotate(modelMatrix, modelRotation.y, glm::vec3(0.0f, 1.0f, 0.0f));
modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f, 0.5f, 0.5f));
glm::mat4 modelMatrix2 = glm::translate(glm::mat4(5.0f), glm::vec3(0.0f, -0.0f, 0.0f));
modelMatrix2 = glm::rotate(modelMatrix2, modelRotation.x, glm::vec3(1.0f, 0.0f, 0.0f));
modelMatrix2 = glm::rotate(modelMatrix2, modelRotation.y, glm::vec3(0.0f, 1.0f, 0.0f));
modelMatrix2 = glm::scale(modelMatrix2, glm::vec3(0.5f, 0.5f, 0.5f));
glm::mat4 mv_matrix = viewMatrix * modelMatrix;
//glm::mat4 mv_matrixlegs = viewMatrix * modelMatrixlegs;
glUniformMatrix4fv(glGetUniformLocation(pipeline.pipe.program, "model_matrix"), 1, GL_FALSE, &modelMatrix[0][0]);
glUniformMatrix4fv(glGetUniformLocation(pipeline.pipe.program, "modelMatrix2"), 1, GL_FALSE, &modelMatrix2[0][0]);
glUniformMatrix4fv(glGetUniformLocation(pipeline.pipe.program, "view_matrix"), 1, GL_FALSE, &viewMatrix[0][0]);
glUniformMatrix4fv(glGetUniformLocation(pipeline.pipe.program, "proj_matrix"), 1, GL_FALSE, &projMatrix[0][0]);
// glUniformMatrix4fv(glGetUniformLocation(pipeline.pipe.program, "modelMatrixlegs"), 1, GL_FALSE, &modelMatrixlegs[0][0]);
// glUniformMatrix4fv(glGetUniformLocation(pipeline.pipe.program, "view_matrix"), 1, GL_FALSE, &viewMatrix[0][0]);
// glUniformMatrix4fv(glGetUniformLocation(pipeline.pipe.program, "proj_matrix"), 1, GL_FALSE, &projMatrix[0][0]);
content.DrawModel(content.vaoAndEbos, content.model);
content2.DrawModel(content2.vaoAndEbos, content2.model);
#if defined(__APPLE__)
glCheckError();
#endif
}
void ui()
{
ImGuiIO &io = ImGui::GetIO();
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration;
window_flags |= ImGuiWindowFlags_AlwaysAutoResize;
window_flags |= ImGuiWindowFlags_NoSavedSettings;
window_flags |= ImGuiWindowFlags_NoFocusOnAppearing;
window_flags |= ImGuiWindowFlags_NoNav;
const auto PAD = 10.0f;
const ImGuiViewport *viewport = ImGui::GetMainViewport();
ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
ImVec2 work_size = viewport->WorkSize;
ImVec2 window_pos, window_pos_pivot;
window_pos.x = work_pos.x + work_size.x - PAD;
window_pos.y = work_pos.y + work_size.y - PAD;
window_pos_pivot.x = 1.0f;
window_pos_pivot.y = 1.0f;
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
window_flags |= ImGuiWindowFlags_NoMove;
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
bool *p_open = NULL;
if (ImGui::Begin("Info", nullptr, window_flags)) {
ImGui::Text("About: 3D Graphics and Animation 2022"); // ImGui::Separator();
ImGui::Text("Performance: %.3fms/Frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Text("Pipeline: %s", pipeline.pipe.error?"ERROR":"OK");
}
ImGui::End();
// Rendering imgui
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
void onResizeCallback(GLFWwindow *window, int w, int h)
{
windowWidth = w;
windowHeight = h;
// Get the correct size in pixels
glfwGetFramebufferSize(window, &windowWidth, &windowHeight);
if (windowWidth > 0 && windowHeight > 0)
{ // Avoid issues when minimising window - it gives size of 0 which fails division.
aspect = (float)w / (float)h;
projMatrix = glm::perspective(glm::radians(fovy), aspect, 0.1f, 1000.0f);
}
}
void onKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if (action == GLFW_PRESS)
keyStatus[key] = true;
else if (action == GLFW_RELEASE)
keyStatus[key] = false;
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
void onMouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
{
}
void onMouseMoveCallback(GLFWwindow *window, double x, double y)
{
int mouseX = static_cast<int>(x);
int mouseY = static_cast<int>(y);
}
void onMouseWheelCallback(GLFWwindow *window, double xoffset, double yoffset)
{
int yoffsetInt = static_cast<int>(yoffset);
}
void APIENTRY openGLDebugCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar *message,
const GLvoid *userParam) // Debugger callback for Win64 - OpenGL versions 4.2 or better.
{
debugger.OpenGLDebugCallback(source, type, id, severity, length, message, userParam);
}
void debugGL() // Debugger function for Win64 - OpenGL versions 4.2 or better.
{
// Enable Opengl Debug
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback((GLDEBUGPROC)openGLDebugCallback, nullptr);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, true);
}
GLenum glCheckError_(const char *file, int line) // Debugger manual function for Apple - OpenGL versions 3.3 to 4.1.
{
GLenum errorCode;
while ((errorCode = glGetError()) != GL_NO_ERROR) debugger.GlGetError(errorCode, file, line);
return errorCode;
}
FragmentShader.glsl
#version 430 core
out vec4 color;
in VS_OUT
{
vec3 vertex;
vec3 normals;
vec2 tc;
} fs_in;
uniform sampler2D tex;
uniform sampler2D model_matrix;
uniform sampler2D modelMatrix2;
void main(void){
color = texture(tex, fs_in.tc);
}
VertexShader.glsl
#version 410 core
layout (location = 0) in vec3 in_vertex;
layout (location = 1) in vec3 in_normals;
layout (location = 2) in vec2 in_tc;
out VS_OUT
{
vec3 vertex;
vec3 normals;
vec2 tc;
} vs_out;
uniform mat4 model_matrix;
uniform mat4 modelMatrixlegs;
uniform mat4 view_matrix;
uniform mat4 proj_matrix;
void main(void)
{
gl_Position = proj_matrix * view_matrix * model_matrix * vec4(in_vertex, 1.0);
vs_out.vertex = in_vertex;
vs_out.normals = in_normals;
vs_out.tc = in_tc;
}
Models don't have positions or rotations or scaling values.
When you call glDrawArrays (or glDrawElements or glDrawElementsIndirect or whatever), then OpenGL renders the current model with the current texture and the current position and rotation and scaling value. Until that point they are separate. You have to realize this - you can draw the same model with different position/rotation/scaling, or the same model with different textures, or different models with the same texture, or so on. There's no need to link them together until you actually draw them and you shouldn't think they are linked together.
I don't see where DrawModel is defined, but I assume it calls glDrawArrays or glDrawElements. So it uses the texture and position and rotation and scaling value (a.k.a. the matrix) that are current when you call it.
So all you have to do is make model 1's matrix current before drawing model 1, and make model 2's matrix current before drawing model 2. Same for the textures.
i.e. probably something like this
glUniformMatrix4fv(glGetUniformLocation(pipeline.pipe.program, "model_matrix"),
1, GL_FALSE, &modelMatrix[0][0]);
// ^^^^^^^^^^^ model 1 matrix
glBindTexture(GL_TEXTURE_2D, texture);
// ^^^^^^^ model 1 texture
content.DrawModel(content.vaoAndEbos, content.model);
//^^^^^ ^^^^^^^ ^^^^^^^^^^^^^ model 1
glUniformMatrix4fv(glGetUniformLocation(pipeline.pipe.program, "model_matrix"),
1, GL_FALSE, &modelMatrix2[0][0]);
// ^^^^^^^^^^^^ model 2 matrix
glBindTexture(GL_TEXTURE_2D, texture2);
// ^^^^^^^^ model 2 texture
content2.DrawModel(content2.vaoAndEbos, content2.model);
//^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^^ model 2
You can delete the modelMatrixlegs variable from the shader because it's not actually doing anything.
in image appearing red opaque but i set the glColor3f(1.0f, 0.0f, 0.0f);
//command compiler g++ console tested with Visual Studio Code
//g++ GL01Hello.cpp -o GL01Hello.exe -L"C:/MinGW/freeglut/lib" -lglu32 -lopengl32 -lfreeglut -I"C:\MinGW\freeglut\include\GL"
/*
* GL01Hello.cpp:With Load Background Image and Poligon Test OpenGL/GLUT C/C++ Setup
* Tested Visual Studio Code with MinGW
* To compile with -lfreeglut -lglu32 -lopengl32 and
*/
#include <windows.h> // for MS Windows
#include <stdio.h> /* printf, scanf, puts, NULL */
#include <iostream>
#include <stdlib.h> /* srand, rand */
#include <ctime>
#include <freeglut.h> // GLUT, include glu.h and gl.h
using namespace std;
float spin = 0.0;
GLuint texture = 0;
int w1 = 0;
int h1 = 0;
// for random color primitive polygon
//static GLubyte redc,greenc,bluec;
bool prim_polygonmode = false;
// glut_load_image
GLuint LoadTexture( const char * filename )
{
GLuint texture;
int width, height;
unsigned char * data;
FILE * file;
file = fopen( filename, "rb" );
if(!file)
std::cout<<"File not Found"<<std::endl;
if ( file == NULL ) return 0;
width = 1360;
height = 768;
data = (unsigned char *)malloc( width * height * 3 );
//int size = fseek(file,);
fread( data, width * height * 3, 1, file );
fclose( file );
for(int i = 0; i < width * height ; ++i)
{
int index = i*3;
unsigned char B,R;
B = data[index];
R = data[index+2];
data[index] = R;
data[index+2] = B;
}
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );//Necessary for correct elements value 4 default
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT );
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,GL_RGB, GL_UNSIGNED_BYTE, data );
free( data );
return texture;
}
/* Initialize OpenGL Graphics just n this case for colors */
void initGL() {
// Set "clearing" or background color
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black and opaque
//randomnumber color by ctime library
srand(time(NULL));
//redc = rand()%255;
//greenc = rand()%255;
//bluec = rand()%255;
}
/* Called back when there is no other event to be handled */
void idle() {
spin = spin + 0.075;
if (spin > 360.0)
spin = 0;
glutPostRedisplay(); // Post a re-paint request to activate display()
}
/* Handler for window re-size event. Called back when the window first appears and
whenever the window is re-sized with its new width and height */
void reshape(GLsizei width, GLsizei height) { // GLsizei for non-negative integer
// Compute aspect ratio of the new window
w1 = width;
h1 = height;
if (height == 0) height = 1; // To prevent divide by 0
GLfloat aspect = (GLfloat)width / (GLfloat)height;
// Set the viewport to cover the new window
glViewport(0, 0, width, height);
// Set the aspect ratio of the clipping area to match the viewport
glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix
glLoadIdentity();
if (width >= height) {
// aspect >= 1, set the height from -1 to 1, with larger width
gluOrtho2D(-1.0 * aspect, 1.0 * aspect, -1.0, 1.0);
} else {
// aspect < 1, set the width to -1 to 1, with larger height
gluOrtho2D(-1.0, 1.0, -1.0 / aspect, 1.0 / aspect);
}
}
void orthogonalStart()
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(-w1/2, w1/2, -h1/2, h1/2);
glMatrixMode(GL_MODELVIEW);
}
void orthogonalEnd()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
void background()
{
glBindTexture( GL_TEXTURE_2D, texture );
orthogonalStart();
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glPolygonOffset(1,1);
// texture width/height
const int iw = 1360;
const int ih = 768;
glPushMatrix();
glTranslatef( -iw/2, -ih/2, 0 );
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f); // always default color white stars, if no this line will random color same of polygon
glTexCoord2i(0,0); glVertex2i(0, 0);
glTexCoord2i(1,0); glVertex2i(iw, 0);
glTexCoord2i(1,1); glVertex2i(iw, ih);
glTexCoord2i(0,1); glVertex2i(0, ih);
glEnd();
glPopMatrix();
orthogonalEnd();
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
glClear(GL_COLOR_BUFFER_BIT);// Clear the color buffer (background
glEnable( GL_TEXTURE_2D );
background();
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// A SQUARE PARAMETERS
if (prim_polygonmode) { // draw polygon mode lines
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
} else {
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glPolygonOffset(1,1);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glRotatef(spin , 0., 0., 1.);
glTranslatef(50.0, 50.0, 0);
glTranslatef(-50.0, -50.0, 0);
glBegin(GL_QUADS); // Each set of 4 vertices form a quad
//glColor3ub(redc, greenc, bluec); // Random red green blue value
glColor3f(1.0f, 0.0f, 0.0f); // Random red green blue value
glVertex2f(-0.5f, -0.5f); // x, y default 0.5f values
glVertex2f( 0.5f, -0.5f);
glVertex2f( 0.5f, 0.5f);
glVertex2f(-0.5f, 0.5f);
glEnd();
//angle += 5.0f;
glPopMatrix();
// glFlush(); // Render now
glutSwapBuffers(); // Double buffered - swap the front and back buffers
}
/* Callback handler for special-key event */
void specialKeys(int key, int x, int y) {
switch (key) {
case GLUT_KEY_F1: // F1: Toggle wireframe and solid polygon
prim_polygonmode = !prim_polygonmode; // Toggle state
break;
}
}
/* Main function: GLUT runs as a console application starting at main() */
int main(int argc, char** argv) {
glutInit(&argc, argv); // Initialize GLUT
glutInitDisplayMode(GLUT_DOUBLE); // Enable double buffered mode
glutInitWindowSize(1360, 768); // Set the window's initial width & height
glutInitWindowPosition(0, 0);
// Position the window's initial top-left corner
glutCreateWindow("OpenGL Setup Test"); // Create a window with the given title
glutSpecialFunc(specialKeys); // Register callback handler for special-key event
glutDisplayFunc(display); // Register display callback handler for window re-paint
glutReshapeFunc(reshape);
glutIdleFunc(idle);
// GLuint texture;
texture = LoadTexture( "stars.bmp" );
initGL();
glutMainLoop();// Enter the event-processing loop
//Free our texture
glDeleteTextures( 1, &texture );
return 0;
}
This code have a set background and small animation of square.
Dont know wihy cant set more the solid colors. Then the wireframe square i got a very litle line red need got the bright color red.Maybe any filte, ou buffer causing that?
if possible please help me.
OpenGL is a state engine. Once a state is set, it is persistent until it is change again.
This means if 2 dimensional texturing is enabled, all the following geometry is "textured".
Note, when glVertex2f is called then the current texture coordinate is associated with the vertex coordinate. If you don't explicitly set a texture coordinate, then the last texture coordinate which was set is still the current texture coordinate and will be associated to the vertex coordinate. This may cause a random like behavior.
If texturing is enabled, then by default the color of the texel is multiplied by the current color, because by default the texture environment mode (GL_TEXTURE_ENV_MODE) is GL_MODULATE. See glTexEnv.
That all means:
If you want to draw a geometry with a texture then enable texturing and set a "white" color:
glEnable(GL_TEXTURE_2D)
glColor3f(1.0f, 1.0f, 1.0f);
background();
If you want to draw a uniform colored geometry, then set the color and disable texturing:
glDisable(GL_TEXTURE_2D);
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_QUADS);
// [...]
glEnd();
I am making changes in the code from this article, to acomplish the same result without need the methods specific for Windows and be able to run the programa in other platforms. I can compile and run the program without errors (with the Main and Render functions listed below), but the result is a blank screen. Someone can find some reason in the code for this issue happen?
Main:
int main(int argc, char **argv)
{
// temp var's
int width = 800;
int height = 600;
int bits = 32;
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(width,height);
glutInit(&argc, argv);
glutCreateWindow("Terrain");
glutDisplayFunc(Render);
glutReshapeFunc(AlteraTamanhoJanela);
glutKeyboardFunc(GerenciaTeclado);
glutMouseFunc(GerenciaMouse);
Initialize();
glutMainLoop();
}
Render:
void Render()
{
radians = float(PI*(angle-90.0f)/180.0f);
// calculate the camera's position
cameraX = lookX + sin(radians)*mouseY; // multiplying by mouseY makes the
cameraZ = lookZ + cos(radians)*mouseY; // camera get closer/farther away with mouseY
cameraY = lookY + mouseY / 2.0f;
// calculate the camera look-at coordinates as the center of the terrain map
lookX = (MAP_X*MAP_SCALE)/2.0f;
lookY = 150.0f;
lookZ = -(MAP_Z*MAP_SCALE)/2.0f;
// clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// set the camera position
gluLookAt(cameraX, cameraY, cameraZ, lookX, lookY, lookZ, 0.0, 1.0, 0.0);
// set the current texture to the land texture
glBindTexture(GL_TEXTURE_2D, land);
// we are going to loop through all of our terrain's data points,
// but we only want to draw one triangle strip for each set along the x-axis.
for (int z = 0; z < MAP_Z-1; z++)
{
//printf("%s %d\n","Loop FOR para Z = ",z);
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < MAP_X-1; x++)
{
//printf("%s %d\n","Loop FOR para X = ",x);
// for each vertex, we calculate the grayscale shade color,
// we set the texture coordinate, and we draw the vertex.
/*
the vertices are drawn in this order:
0 ---> 1
/
/
|/
2 ---> 3
*/
// draw vertex 0
//printf("%s\n","Primeiro");
glColor3f(terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(terrain[x][z][0], terrain[x][z][1], terrain[x][z][2]);
// draw vertex 1
//printf("%s\n","Segundo");
glTexCoord2f(1.0f, 0.0f);
glColor3f(terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f);
glVertex3f(terrain[x+1][z][0], terrain[x+1][z][1], terrain[x+1][z][2]);
// draw vertex 2
//printf("%s\n","Terceiro");
glTexCoord2f(0.0f, 1.0f);
glColor3f(terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f);
glVertex3f(terrain[x][z+1][0], terrain[x][z+1][1], terrain[x][z+1][2]);
// draw vertex 3
//printf("%s\n","Quarto");
glColor3f(terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(terrain[x+1][z+1][0], terrain[x+1][z+1][1], terrain[x+1][z+1][2]);
}
glEnd();
}
// enable blending
glEnable(GL_BLEND);
// enable read-only depth buffer
glDepthMask(GL_FALSE);
// set the blend function to what we use for transparency
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
// set back to normal depth buffer mode (writable)
glDepthMask(GL_TRUE);
// disable blending
glDisable(GL_BLEND);
glFlush();
//SwapBuffers(g_HDC); // bring backbuffer to foreground
}
Update: As requested, here is the other functions from my code.
void InitializeTerrain()
{
// loop through all of the heightfield points, calculating
// the coordinates for each point
for (int z = 0; z < MAP_Z; z++)
{
for (int x = 0; x < MAP_X; x++)
{
terrain[x][z][0] = float(x)*MAP_SCALE;
terrain[x][z][1] = (float)imageData[(z*MAP_Z+x)*3];
terrain[x][z][2] = -float(z)*MAP_SCALE;
}
}
}
void CleanUp()
{
free(imageData);
free(landTexture);
}
// Initialize
// desc: initializes OpenGL
void Initialize()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // clear to black
glShadeModel(GL_SMOOTH); // use smooth shading
glEnable(GL_DEPTH_TEST); // hidden surface removal
glEnable(GL_CULL_FACE); // do not calculate inside of poly's
glFrontFace(GL_CCW); // counter clock-wise polygons are out
glEnable(GL_TEXTURE_2D); // enable 2D texturing
imageData = LoadBitmapFile("terrain2.bmp", &bitmapInfoHeader);
// initialize the terrain data and load the textures
InitializeTerrain();
LoadTextures();
}
// Função callback chamada quando o tamanho da janela é alterado
void AlteraTamanhoJanela(GLsizei w, GLsizei h)
{
int width, height;
height = h; // retrieve width and height
width = w;
if (height==0) // don't want a divide by zero
{
height=1;
}
glViewport(0, 0, width, height); // reset the viewport to new dimensions
glMatrixMode(GL_PROJECTION); // set projection matrix current matrix
glLoadIdentity(); // reset projection matrix
// calculate aspect ratio of window
gluPerspective(54.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);
glMatrixMode(GL_MODELVIEW); // set modelview matrix
glLoadIdentity(); // reset modelview matrix
}
// Função callback chamada para gerenciar eventos do mouse
void GerenciaMouse(int button, int state, int x, int y)
{
int oldMouseX, oldMouseY;
// save old mouse coordinates
oldMouseX = mouseX;
oldMouseY = mouseY;
// get mouse coordinates from Windows
mouseX = x;
mouseY = y;
// these lines limit the camera's range
if (mouseY < 200)
mouseY = 200;
if (mouseY > 450)
mouseY = 450;
if ((mouseX - oldMouseX) > 0) // mouse moved to the right
angle += 3.0f;
else if ((mouseX - oldMouseX) < 0) // mouse moved to the left
angle -= 3.0f;
glutPostRedisplay();
}
/* Key press processing */
void GerenciaTeclado(unsigned char c, int x, int y)
{
if(c == 27) exit(0);
}
And, finally, the content from file vkgllib.h, included by source code file above:
#include <iostream>
#include <fstream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define WINDOW_WIDTH 640 // Window Width Default
#define WINDOW_HEIGHT 480 // Window Height Default
// definition of PI
#define PI 3.14159265
// Used to defien the title of the window
#define WINDOW_TITLE "OpenGL Terrain Generation"
// A simple structure to define a point whose coordinates are integers
/*typedef struct { GLint x, y; } GLintPoint;
// This structure is used to store the vertices of a polyline
typedef struct { int num; GLintPoint pt[100]; } GLintPointArray;
// Data for an Icosahedron
#define ICO_X 0.525731112119133606
#define ICO_Z 0.850650808352039932*/
/*static GLfloat vdataICO[12][3] =
{
{ -ICO_X, 0.0, ICO_Z }, { ICO_X, 0.0, ICO_Z }, { -ICO_X, 0.0, -ICO_Z }, { ICO_X, 0.0, -ICO_Z },
{ 0.0, ICO_Z, ICO_X }, { 0.0, ICO_Z, -ICO_X }, { 0.0, -ICO_Z, ICO_X }, { 0.0, -ICO_Z, -ICO_X },
{ ICO_Z, ICO_X, 0.0 }, { -ICO_Z, ICO_X, 0.0 }, { ICO_Z, -ICO_X, 0.0 }, { -ICO_Z, -ICO_X, 0.0 }
};
static GLuint tindicesICO[20][3] =
{
{ 1, 4, 0 }, { 4, 9, 0 }, { 4, 5, 9 }, { 8, 5, 4 }, { 1, 8, 4 },
{ 1, 10, 8 }, { 10, 3, 8 }, { 8, 3, 5 }, { 3, 2, 5 }, { 3, 7, 2 },
{ 3, 10, 7 }, { 10, 6, 7 }, { 6, 11, 7 }, { 6, 0, 11 }, {6, 1, 0 },
{ 10, 1, 6 }, { 11, 0, 9 }, { 2, 11, 9 }, { 5, 2, 9 }, { 11, 2, 7 }
};*/
// Data for Tetrahedron
static GLfloat P1T[3] = { -2, 3, 0 };
static GLfloat P2T[3] = { -3, 0, 0 };
static GLfloat P3T[3] = { -1, 0, 3 };
static GLfloat P4T[3] = { -4, 0, 0 };
// Calculating the Normalized Cross Product of Two Vectors
void normalize( float v[3] )
{
GLfloat d = sqrt( float(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) );
if( d==0.0 )
{
cerr<<"zero length vector"<<endl;
return;
}
v[0] /= d;
v[1] /= d;
v[2] /= d;
}
void normcrossprod( float v1[3], float v2[3], float out[3] )
{
out[0] = v1[1]*v2[2] - v1[2]*v2[1];
out[1] = v1[2]*v2[0] - v1[0]*v2[2];
out[2] = v1[0]*v2[1] - v1[1]*v2[0];
normalize( out );
}
////// Defines
#define BITMAP_ID 0x4D42 // the universal bitmap ID
#define MAP_X 32 // size of map along x-axis
#define MAP_Z 32 // size of map along z-axis
#define MAP_SCALE 20.0f // the scale of the terrain map
////// Texture Information
BITMAPINFOHEADER bitmapInfoHeader; // temp bitmap info header
BITMAPINFOHEADER landInfo; // land texture info header
BITMAPINFOHEADER waterInfo; // water texture info header
//AUX_RGBImageRec
unsigned char* imageData; // the map image data
unsigned char* landTexture; // land texture data
unsigned int land; // the land texture object
////// Terrain Data
float terrain[MAP_X][MAP_Z][3]; // heightfield terrain data (0-255); 256x256
// LoadBitmapFile
// desc: Returns a pointer to the bitmap image of the bitmap specified
// by filename. Also returns the bitmap header information.
// No support for 8-bit bitmaps.
unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{
FILE *filePtr; // the file pointer
BITMAPFILEHEADER bitmapFileHeader; // bitmap file header
unsigned char *bitmapImage; // bitmap image data
int imageIdx = 0; // image index counter
unsigned char tempRGB; // swap variable
// open filename in "read binary" mode
filePtr = fopen(filename, "rb");
if (filePtr == NULL)
return NULL;
// read the bitmap file header
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// verify that this is a bitmap by checking for the universal bitmap id
if (bitmapFileHeader.bfType != BITMAP_ID)
{
fclose(filePtr);
return NULL;
}
// read the bitmap information header
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// move file pointer to beginning of bitmap data
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// allocate enough memory for the bitmap image data
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
// verify memory allocation
if (!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
return NULL;
}
// read in the bitmap image data
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
// make sure bitmap image data was read
if (bitmapImage == NULL)
{
fclose(filePtr);
return NULL;
}
// swap the R and B values to get RGB since the bitmap color format is in BGR
for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
// close the file and return the bitmap image data
fclose(filePtr);
return bitmapImage;
}
bool LoadTextures()
{
// load the land texture data
landTexture = LoadBitmapFile("green.bmp", &landInfo);
if (!landTexture)
return false;
// generate the land texture as a mipmap
glGenTextures(1, &land);
glBindTexture(GL_TEXTURE_2D, land);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, landInfo.biHeight, landInfo.biWidth, GL_RGB, GL_UNSIGNED_BYTE, landTexture);
return true;
}
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
^^^^^^^^^^^
You've asked for double-buffering.
And yet your Render() function seems to assume you're using single-buffering:
void Render()
{
...
glFlush();
}
Either switch to GLUT_SINGLE or use glutSwapBuffers() instead of glFlush().
I'm using OpenGl to animate a graph that looks something like this:
Here's the code I've got so far:
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0,1,0); //Green
// Frequency Line
glLineWidth(3.0);
glBegin(GL_LINE_STRIP);
glVertex2f(-1,0);
glVertex2f(x1,y1);
glEnd();
y1 = randVarGen();
x1 = randVarGen();
and I have a timer to redraw the graph every 50 ms. I want to start with a straight line and based on variables from an audio file(I'm using random variables for now), the graph should go up and down sort of like a music visualizer.
You need to sample the function you want to plot.
glBegin(GL_LINE_STRIP);
glVertex2f(0f, 0f);
for (float x = 1f; x < 100f; x += 1f)
glVertex2f(x, randVarGen());
glVertex2f(100f, 0f);
glEnd();
Wikibooks OpenGL tutorial example
Tested on Ubuntu 16.04.
https://en.wikibooks.org/wiki/OpenGL_Programming/Scientific_OpenGL_Tutorial_01
https://gitlab.com/wikibooks-opengl/modern-tutorials/tree/2d8a441d8db81b4a619cf583769d1ea1451f4529/graph01
The key files of that repo are:
graph.cpp
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include "../common/shader_utils.h"
#include "res_texture.c"
GLuint program;
GLint attribute_coord2d;
GLint uniform_offset_x;
GLint uniform_scale_x;
GLint uniform_sprite;
GLuint texture_id;
GLint uniform_mytexture;
float offset_x = 0.0;
float scale_x = 1.0;
int mode = 0;
struct point {
GLfloat x;
GLfloat y;
};
GLuint vbo;
int init_resources() {
program = create_program("graph.v.glsl", "graph.f.glsl");
if (program == 0)
return 0;
attribute_coord2d = get_attrib(program, "coord2d");
uniform_offset_x = get_uniform(program, "offset_x");
uniform_scale_x = get_uniform(program, "scale_x");
uniform_sprite = get_uniform(program, "sprite");
uniform_mytexture = get_uniform(program, "mytexture");
if (attribute_coord2d == -1 || uniform_offset_x == -1 || uniform_scale_x == -1 || uniform_sprite == -1 || uniform_mytexture == -1)
return 0;
/* Enable blending */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* Enable point sprites (not necessary for true OpenGL ES 2.0) */
#ifndef GL_ES_VERSION_2_0
glEnable(GL_POINT_SPRITE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif
/* Upload the texture for our point sprites */
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, res_texture.width, res_texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, res_texture.pixel_data);
// Create the vertex buffer object
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Create our own temporary buffer
point graph[2000];
// Fill it in just like an array
for (int i = 0; i < 2000; i++) {
float x = (i - 1000.0) / 100.0;
graph[i].x = x;
graph[i].y = sin(x * 10.0) / (1.0 + x * x);
}
// Tell OpenGL to copy our array to the buffer object
glBufferData(GL_ARRAY_BUFFER, sizeof graph, graph, GL_STATIC_DRAW);
return 1;
}
void display() {
glUseProgram(program);
glUniform1i(uniform_mytexture, 0);
glUniform1f(uniform_offset_x, offset_x);
glUniform1f(uniform_scale_x, scale_x);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
/* Draw using the vertices in our vertex buffer object */
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(attribute_coord2d);
glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, GL_FALSE, 0, 0);
/* Push each element in buffer_vertices to the vertex shader */
switch (mode) {
case 0:
glUniform1f(uniform_sprite, 0);
glDrawArrays(GL_LINE_STRIP, 0, 2000);
break;
case 1:
glUniform1f(uniform_sprite, 1);
glDrawArrays(GL_POINTS, 0, 2000);
break;
case 2:
glUniform1f(uniform_sprite, res_texture.width);
glDrawArrays(GL_POINTS, 0, 2000);
break;
}
glutSwapBuffers();
}
void special(int key, int x, int y) {
switch (key) {
case GLUT_KEY_F1:
mode = 0;
printf("Now drawing using lines.\n");
break;
case GLUT_KEY_F2:
mode = 1;
printf("Now drawing using points.\n");
break;
case GLUT_KEY_F3:
mode = 2;
printf("Now drawing using point sprites.\n");
break;
case GLUT_KEY_LEFT:
offset_x -= 0.1;
break;
case GLUT_KEY_RIGHT:
offset_x += 0.1;
break;
case GLUT_KEY_UP:
scale_x *= 1.5;
break;
case GLUT_KEY_DOWN:
scale_x /= 1.5;
break;
case GLUT_KEY_HOME:
offset_x = 0.0;
scale_x = 1.0;
break;
}
glutPostRedisplay();
}
void free_resources() {
glDeleteProgram(program);
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(640, 480);
glutCreateWindow("My Graph");
GLenum glew_status = glewInit();
if (GLEW_OK != glew_status) {
fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status));
return 1;
}
if (!GLEW_VERSION_2_0) {
fprintf(stderr, "No support for OpenGL 2.0 found\n");
return 1;
}
GLfloat range[2];
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
if (range[1] < res_texture.width)
fprintf(stderr, "WARNING: point sprite range (%f, %f) too small\n", range[0], range[1]);
printf("Use left/right to move horizontally.\n");
printf("Use up/down to change the horizontal scale.\n");
printf("Press home to reset the position and scale.\n");
printf("Press F1 to draw lines.\n");
printf("Press F2 to draw points.\n");
printf("Press F3 to draw point sprites.\n");
if (init_resources()) {
glutDisplayFunc(display);
glutSpecialFunc(special);
glutMainLoop();
}
free_resources();
return 0;
}
graph.f.glsl
uniform sampler2D mytexture;
varying vec4 f_color;
uniform float sprite;
void main(void) {
if (sprite > 1.0)
gl_FragColor = texture2D(mytexture, gl_PointCoord) * f_color;
else
gl_FragColor = f_color;
}
graph.v.glsl
attribute vec2 coord2d;
varying vec4 f_color;
uniform float offset_x;
uniform float scale_x;
uniform lowp float sprite;
void main(void) {
gl_Position = vec4((coord2d.x + offset_x) * scale_x, coord2d.y, 0, 1);
f_color = vec4(coord2d.xy / 2.0 + 0.5, 1, 1);
gl_PointSize = max(1.0, sprite);
}
I want to draw a 2D array of pixel data (RGB / grayscale values) on the screen as fast as possible, using OpenGL. The pixel data changes frequently.
I had hoped that I would find a simple function that would let me push in a pointer to an array representing the pixel data, since this is probably the fastest approach. Unfortunately, I have found no such function.
What is the best way to accomplish this task?
Maybe glDrawPixels is the function you are looking for? Though if the data is static it would be better to create a texture with it, and then draw that each frame.
I recently had a similar problem, as I am trying to render a video to screen (ie repeatedly upload pixel data to the VRAM), my approach is:
use glTexImage2D and glTexSubImage2D to upload the data to the texture (ie bind the texture (and texture unit, if applicable) before calling that)
in my case as the video frame rate (usually about 24 fps) is lower than the framerate of my application (aimed at 60 fps), in order to avoid uploading the same data again I use a framebuffer object (check out glGenFramebuffers/glBindFramebuffer/glDeleteFramebuffers) and link my texture with the framebuffer (glFramebufferTexture2D). I then upload that texture once, and draw the same frame multiple times (just normal texture access with glBindTexture)
I don't know which platform you are using, but as I am targetting Mac I use some Apple extensions to ensure the data transfer to the VRAM happens through DMA (ie make glTexSubImage2D return immediately to let the CPU do other work) - please feel free to ask me for more info if you are using Mac too
also as you are using just grayscale, you might want to consider just using a GL_LUMINANCE texture (ie 1 byte per pixel) rather than RGB based format to make the upload faster (but that depends on the size of your texture data, I was streaming HD 1920x1080 video so I needed to make sure to keep it down)
also be aware of the format your hardware is using to avoid unnecessary data conversions (ie normally it seems better to use BGRA data than for example just RGB)
finally, in my code I replaced all the fixed pipeline functionality with shaders (in particular the conversion of the data from grayscale or YUV format to RGB), but again all that depends on the size of your data, and the workload of your CPU or GPU
Hope this helps, feel free to message me if you need further info
I would think the fastest way would be to draw a screen sized quad with ortho projection and use a pixel shader and Texture Buffer Object to draw directly to the texture in the pixel shader. Due to latency transferring to/from the TBO you may want to see if double buffering would help.
If speed isn't much of a concern (you just need fairly interactive framerates) glDrawPixels is easy to use and works well enough for many purposes.
My solution for getting dynamically changing image data to the screen in OpenGL,
#define WIN32_LEAN_AND_MEAN
#include "wx/wx.h"
#include "wx/sizer.h"
#include "wx/glcanvas.h"
#include "BasicGLPane.h"
// include OpenGL
#ifdef __WXMAC__
#include "OpenGL/glu.h"
#include "OpenGL/gl.h"
#else
#include <GL/glu.h>
#include <GL/gl.h>
#endif
#include "ORIScanMainFrame.h"
BEGIN_EVENT_TABLE(BasicGLPane, wxGLCanvas)
EVT_MOTION(BasicGLPane::mouseMoved)
EVT_LEFT_DOWN(BasicGLPane::mouseDown)
EVT_LEFT_UP(BasicGLPane::mouseReleased)
EVT_RIGHT_DOWN(BasicGLPane::rightClick)
EVT_LEAVE_WINDOW(BasicGLPane::mouseLeftWindow)
EVT_SIZE(BasicGLPane::resized)
EVT_KEY_DOWN(BasicGLPane::keyPressed)
EVT_KEY_UP(BasicGLPane::keyReleased)
EVT_MOUSEWHEEL(BasicGLPane::mouseWheelMoved)
EVT_PAINT(BasicGLPane::render)
END_EVENT_TABLE()
// Test data for image generation. floats range 0.0 to 1.0, in RGBRGBRGB... order.
// Array is 1024 * 3 long. Note that 32 * 32 is 1024 and is the largest image we can randomly generate.
float* randomFloatRGB;
float* randomFloatRGBGrey;
BasicGLPane::BasicGLPane(wxFrame* parent, int* args) :
wxGLCanvas(parent, wxID_ANY, args, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
{
m_context = new wxGLContext(this);
randomFloatRGB = new float[1024 * 3];
randomFloatRGBGrey = new float[1024 * 3];
// In GL images 0,0 is in the lower left corner so the draw routine does a vertical flip to get 'regular' images right side up.
for (int i = 0; i < 1024; i++) {
// Red
randomFloatRGB[i * 3] = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
// Green
randomFloatRGB[i * 3 + 1] = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
// Blue
randomFloatRGB[i * 3 + 2] = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
// Telltale 2 white pixels in 0,0 corner.
if (i < 2) {
randomFloatRGB[i * 3] = randomFloatRGB[i * 3 + 1] = randomFloatRGB[i * 3 + 2] = 1.0f;
}
randomFloatRGBGrey[i * 3] = randomFloatRGB[i * 3];
randomFloatRGBGrey[i * 3 + 1] = randomFloatRGB[i * 3];
randomFloatRGBGrey[i * 3 + 2] = randomFloatRGB[i * 3];
}
// To avoid flashing on MSW
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
}
BasicGLPane::~BasicGLPane()
{
delete m_context;
}
void BasicGLPane::resized(wxSizeEvent& evt)
{
// wxGLCanvas::OnSize(evt);
Refresh();
}
int BasicGLPane::getWidth()
{
return GetSize().x;
}
int BasicGLPane::getHeight()
{
return GetSize().y;
}
void BasicGLPane::render(wxPaintEvent& evt)
{
assert(GetParent());
assert(GetParent()->GetParent());
ORIScanMainFrame* mf = dynamic_cast<ORIScanMainFrame*>(GetParent()->GetParent());
assert(mf);
switch (mf->currentMainView) {
case ORIViewSelection::ViewCamera:
renderCamera(evt);
break;
case ORIViewSelection::ViewDepth:
renderDepth(evt);
break;
case ORIViewSelection::ViewPointCloud:
renderPointCloud(evt);
break;
case ORIViewSelection::View3DModel:
render3DModel(evt);
break;
default:
renderNone(evt);
}
}
void BasicGLPane::renderNone(wxPaintEvent& evt) {
if (!IsShown())
return;
SetCurrent(*(m_context));
glPushAttrib(GL_ALL_ATTRIB_BITS);
glClearColor(0.08f, 0.11f, 0.15f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFlush();
SwapBuffers();
glPopAttrib();
}
GLuint makeOpenGlTextureFromDataLuninanceFloats(int width, int height, float* f) {
GLuint textureID;
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &textureID);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, textureID);
// Give the image to OpenGL
glTexImage2D(GL_TEXTURE_2D, 0, GL_FLOAT, width, height, 0, GL_FLOAT, GL_LUMINANCE, f);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
GLuint makeOpenGlTextureFromRGBInts(int width, int height, unsigned int* f) {
GLuint textureID;
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &textureID);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, textureID);
// Give the image to OpenGL
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT, f);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
/// <summary>
/// Range of each float is 0.0f to 1.0f
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="floatRGB"></param>
/// <returns></returns>
GLuint makeOpenGlTextureFromRGBFloats(int width, int height, float* floatRGB) {
GLuint textureID;
// 4.6.0 NVIDIA 457.30 (R Keene machine, 11/25/2020)
// auto sss = glGetString(GL_VERSION);
glGenTextures(1, &textureID);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, textureID);
// Give the image to OpenGL
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, floatRGB);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
void BasicGLPane::DrawTextureToScreenFloat(int w, int h, float* floatDataPtr, GLuint (*textureFactory)(int width, int height, float* floatRGB)) {
if (w <= 0 || h <= 0 || floatDataPtr == NULL || w > 5000 || h > 5000) {
assert(false);
return;
}
SetCurrent(*(m_context));
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushMatrix();
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
glClearColor(0.15f, 0.11f, 0.02f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// 4.6.0 NVIDIA 457.30 (R Keene machine, 11/25/2020)
// auto sss = glGetString(GL_VERSION);
float onePixelW = (float)getWidth() / (float)w;
float onePixelH = (float)getHeight() / (float)h;
float orthoW = w;
float orthoH = h;
if (onePixelH > onePixelW) {
orthoH = h * onePixelH / onePixelW;
}
else {
orthoW = w * onePixelW / onePixelH;
}
// We want the image at the top of the window, not the bottom if the window is too tall.
int topOfScreen = (float)getHeight() / onePixelH;
// If the winjdow resizes after creation you need to change the viewport.
glViewport(0, 0, getWidth(), getHeight());
gluOrtho2D(0.0, orthoW, (double)topOfScreen - (double)orthoH, topOfScreen);
GLuint myTextureName = textureFactory(w, h, floatDataPtr);
glBegin(GL_QUADS);
{
// This order of UV coords and verticies will do the vertical flip of the image to get the 'regular' image 0,0
// in the top left corner.
glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(0.0f + w, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(0.0f + w, 0.0f + h, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 0.0f + h, 0.0f);
}
glEnd();
glDeleteTextures(1, &myTextureName);
glFlush();
SwapBuffers();
glPopClientAttrib();
glPopMatrix();
glPopAttrib();
}
void BasicGLPane::DrawTextureToScreenMat(wxPaintEvent& evt, cv::Mat m, float brightness) {
m.type();
if (m.empty()) {
renderNone(evt);
return;
}
if (m.type() == CV_32FC1) { // Grey scale.
DrawTextureToScreenFloat(m.cols, m.rows, (float*)m.data, makeOpenGlTextureFromDataLuninanceFloats);
}
if (m.type() == CV_32FC3) { // Color.
DrawTextureToScreenFloat(m.cols, m.rows, (float*)m.data, makeOpenGlTextureFromRGBFloats);
}
else {
renderNone(evt);
}
}
void BasicGLPane::renderCamera(wxPaintEvent& evt) {
if (!IsShown())
return;
DrawTextureToScreenMat(evt, ORITopControl::Instance->im_white);
}
void BasicGLPane::renderDepth(wxPaintEvent& evt) {
if (!IsShown())
return;
DrawTextureToScreenMat(evt, ORITopControl::Instance->depth_map);
}
void BasicGLPane::render3DModel(wxPaintEvent& evt) {
if (!IsShown())
return;
SetCurrent(*(m_context));
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushMatrix();
glClearColor(0.08f, 0.11f, 0.15f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFlush();
SwapBuffers();
glPopMatrix();
glPopAttrib();
}
void BasicGLPane::renderPointCloud(wxPaintEvent& evt) {
if (!IsShown())
return;
boost::unique_lock<boost::mutex> lk(ORITopControl::Instance->pointCloudCacheMutex);
SetCurrent(*(m_context));
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, getWidth(), getHeight());
glClearColor(0.08f, 0.11f, 0.15f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (ORITopControl::Instance->pointCloudCache.size() > 0) {
glMatrixMode(GL_PROJECTION);
gluPerspective( /* field of view in degree */ 40.0,
/* aspect ratio */ 1.0,
/* Z near */ 1.0, /* Z far */ 500.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(100, 70, 200, // Eye
25, 25, 25, // Look at pt
0, 0, 1); // Up Vector
glPointSize(2.0);
glBegin(GL_POINTS);
// Use explicit for loop because pointCloudFragments can grow asynchronously.
for (int i = 0; i < ORITopControl::Instance->pointCloudCache.size(); i++) {
auto frag = ORITopControl::Instance->pointCloudCache[i];
auto current_point_cloud_ptr = frag->cloud;
glPushMatrix();
// glMultMatrixf(frag->xform.data());
for (size_t n = 0; n < current_point_cloud_ptr->size(); n++) {
glColor3ub(255, 255, 255);
glVertex3d(current_point_cloud_ptr->points[n].x, current_point_cloud_ptr->points[n].y, current_point_cloud_ptr->points[n].z);
}
glPopMatrix();
}
glEnd();
}
glFlush();
SwapBuffers();
glPopMatrix();
glPopAttrib();
}