Created
January 8, 2025 21:24
-
-
Save hydrodog/b8b54b9a26fb0c1af978eda7bfbd32d2 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#include <GL/glew.h> | |
#include "common/common.hh" | |
#include <glm/glm.hpp> | |
#include <glm/ext.hpp> | |
#include <numbers> | |
#include <iostream> | |
#include <iomanip> | |
#include <cstdint> | |
#include <string> | |
using namespace std; | |
using namespace glm; | |
using namespace std::numbers; | |
class Sphere { | |
private: | |
uint32_t progid; // handle to the shader code | |
uint32_t vao; // array object container for vbo and indices | |
uint32_t vbo; // handle to the point data on the graphics card | |
uint32_t lbo; // handle to buffer of indices for lines for wireframe sphere | |
uint32_t latRes, lonRes; | |
uint32_t resolution; | |
uint32_t indexSize; | |
public: | |
/** | |
* @brief Construct a sphere | |
* | |
* @param r radius of the sphere | |
* @param latRes resolution of the grid in latitude | |
* @param lonRes resolution of the grid in latitude | |
* @param texturePath path to the texture image | |
*/ | |
Sphere(double r, uint32_t latRes, uint32_t lonRes); | |
~Sphere() { cleanup(); } | |
void render(mat4& trans, GLuint textureID); | |
void cleanup(); | |
}; | |
Sphere::Sphere(double r, uint32_t latRes, uint32_t lonRes) : latRes(latRes), lonRes(lonRes), | |
resolution((2*latRes-1)*lonRes + 2) { | |
progid = loadShaders("06b_texturepoints.vert", "06b_textures.frag"); | |
// progid = loadShaders("03gouraud.vert", "03gouraud.frag"); | |
double dlon = 2.0*numbers::pi / lonRes, dlat = numbers::pi / (2*latRes); | |
double z; | |
double lat = -numbers::pi/2 + dlat; // latitude in radians | |
double rcircle; | |
float vert[resolution*5]; // x,y,z,u,v | |
uint32_t c = 0; | |
for (uint32_t j = 0; j < 2*latRes-1; j++, lat += dlat) { | |
//what is the radius of hte circle at that height? | |
rcircle = r* cos(lat); // size of the circle at this latitude | |
z = r * sin(lat); // height of each circle | |
cout << "z=" << z << endl; | |
double t = 0; | |
for (uint32_t i = 0; i < lonRes; i++, t += dlon) { | |
vert[c++] = rcircle * cos(t), vert[c++] = rcircle * sin(t); | |
vert[c++] = z; | |
vert[c++] = 0.5 + 0.5 * cos(t) / lonRes; | |
vert[c++] = 0.5 - 0.5 * sin(t) / lonRes; | |
} | |
cout << endl; | |
} | |
// south pole | |
vert[c++] = 0; | |
vert[c++] = 0; | |
vert[c++] = -r; | |
vert[c++] = 0.5; | |
vert[c++] = 0.5; | |
// north pole | |
vert[c++] = 0; | |
vert[c++] = 0; | |
vert[c++] = r; | |
vert[c++] = 0.5; | |
vert[c++] = 0.5; | |
cout << "resolution: " << resolution << endl; | |
cout << "predicted num vert components: " << resolution*5 << endl; | |
cout << "actual num vert components: " << c << endl; | |
indexSize = resolution * 2 + (2*latRes-1) + lonRes; | |
//TODO: North and South Poles aren't used | |
uint32_t indices[indexSize]; // connect every point in circles or latitude and longitude | |
c = 0; | |
for (uint32_t j = 0; j < 2*latRes - 2; j++) { | |
for (uint32_t i = 0; i < lonRes; i++) { | |
uint32_t current = j * lonRes + i; | |
uint32_t next = (j + 1) * lonRes + i; | |
indices[c++] = current; | |
indices[c++] = next; | |
} | |
// Add degenerate triangles to connect strips | |
indices[c++] = (j + 1) * lonRes + (lonRes - 1); | |
indices[c++] = (j + 1) * lonRes; | |
} | |
cout << "predicted grid points: " << indexSize << endl; | |
cout << "actual grid indices: " << c << endl; | |
// Print index data | |
cout << "Index data: " ; | |
for (size_t i = 0; i < indexSize; i += 2) { | |
cout << '(' << indices[i] << ", " << indices[i+1] << ") "; | |
} | |
glGenVertexArrays(1, &vao); | |
glBindVertexArray(vao); | |
glGenBuffers(1, &vbo); | |
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
glBufferData(GL_ARRAY_BUFFER, resolution*5*sizeof(float), vert, GL_STATIC_DRAW); | |
glGenBuffers(1, &lbo); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lbo); | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexSize*sizeof(uint32_t), indices, GL_STATIC_DRAW); | |
glBindVertexArray(0); | |
} | |
void Sphere::render(mat4& trans, GLuint textureID) { | |
glUseProgram(progid); // Use the shader | |
uint32_t matrixID = glGetUniformLocation(progid, "transform"); | |
glUniformMatrix4fv(matrixID, 1, GL_FALSE, &trans[0][0]); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, textureID); | |
glUniform1i(glGetUniformLocation(progid, "textureSampler"), 0); | |
glBindVertexArray(vao); | |
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); // Position | |
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); // Texture coordinates | |
glEnableVertexAttribArray(0); | |
glEnableVertexAttribArray(1); | |
glDrawArrays(GL_TRIANGLE_STRIP, 0, lonRes*2); | |
glDisableVertexAttribArray(0); | |
glDisableVertexAttribArray(1); | |
glBindVertexArray(0); | |
} | |
void Sphere::cleanup() { | |
glDeleteBuffers(1, &vbo); // remove vbo memory from graphics card | |
glDeleteBuffers(1, &lbo); // remove lbo (line indices) | |
glDeleteVertexArrays(1, &vao); // remove vao from graphics card | |
glDeleteProgram(progid); | |
} | |
using namespace std; | |
using namespace numbers; | |
void glmain() { | |
win = createWindow(800, 800, "Sphere demo"); | |
glClearColor(0.0f, 0.0f, 0.4f, 0.0f); // Dark blue background | |
GLuint textureID = loadWebPTexture("earth.webp"); // Load the texture | |
Sphere sphere(1.0, 3, 3); | |
float rotAngle = 0, dRotAngle = 0.0052; | |
mat4 northup = rotate(mat4(1.0f), float(-numbers::pi/4), vec3(1, 0, 0)); | |
// mat4 northup = mat4(1.0f); | |
vec3 up(0, 1, 0); // normal OpenGL coordinates, x positive to right, y is up (z positive out of screen) | |
do { | |
mat trans = rotate(northup, radians(23.5f), vec3(0, 0, 1)); // tilt axis | |
trans = rotate(trans, rotAngle, vec3(0, 1, 0)); // spin on axis | |
rotAngle += dRotAngle; | |
glClear(GL_COLOR_BUFFER_BIT); // Clear the screen | |
glDisable(GL_DEPTH_TEST); | |
sphere.render(trans, textureID); | |
glfwSwapBuffers(win); // double buffer | |
glfwPollEvents(); | |
} while (glfwGetKey(win, GLFW_KEY_ESCAPE) != GLFW_PRESS && | |
glfwWindowShouldClose(win) == 0); | |
glDeleteTextures(1, &textureID); // Clean up the texture | |
} |
This file contains hidden or 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
#version 330 core | |
layout(location = 0) in vec3 pos; // Position (x, y, z) | |
layout(location = 1) in vec2 texCoord; // Texture coordinates (u, v) | |
uniform mat4 transform; | |
out vec2 TexCoord; | |
void main() { | |
gl_Position = transform * vec4(pos, 1.0); | |
TexCoord = texCoord; | |
} |
This file contains hidden or 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
#version 330 core | |
in vec2 TexCoord; | |
out vec4 FragColor; | |
uniform sampler2D textureSampler; | |
void main() { | |
FragColor = texture(textureSampler, TexCoord); | |
} |
This file contains hidden or 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
#include <stdio.h> | |
#include <string> | |
#include <vector> | |
#include <iostream> | |
#include <iomanip> | |
#include <fstream> | |
#include <algorithm> | |
#include <sstream> | |
#include <webp/decode.h> | |
using namespace std; | |
#include <stdlib.h> | |
#include <string.h> | |
#include <GL/glew.h> | |
#include "common.hh" | |
GLFWwindow* win = nullptr; | |
GLuint loadShaders(const char vertexPath[], const char * fragmentPath) { | |
// Create the shaders | |
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); | |
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); | |
// Read the Vertex Shader code from the file | |
std::string VertexShaderCode; | |
std::ifstream VertexShaderStream(vertexPath, std::ios::in); | |
if(VertexShaderStream.is_open()){ | |
std::stringstream sstr; | |
sstr << VertexShaderStream.rdbuf(); | |
VertexShaderCode = sstr.str(); | |
VertexShaderStream.close(); | |
}else{ | |
printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertexPath); | |
getchar(); | |
return 0; | |
} | |
// Read the Fragment Shader code from the file | |
std::string FragmentShaderCode; | |
std::ifstream FragmentShaderStream(fragmentPath, std::ios::in); | |
if(FragmentShaderStream.is_open()){ | |
std::stringstream sstr; | |
sstr << FragmentShaderStream.rdbuf(); | |
FragmentShaderCode = sstr.str(); | |
FragmentShaderStream.close(); | |
} | |
GLint Result = GL_FALSE; | |
int InfoLogLength; | |
// Compile Vertex Shader | |
printf("Compiling shader : %s\n", vertexPath); | |
char const * VertexSourcePointer = VertexShaderCode.c_str(); | |
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); | |
glCompileShader(VertexShaderID); | |
// Check Vertex Shader | |
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); | |
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); | |
if ( InfoLogLength > 0 ){ | |
std::vector<char> VertexShaderErrorMessage(InfoLogLength+1); | |
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); | |
printf("%s\n", &VertexShaderErrorMessage[0]); | |
} | |
// Compile Fragment Shader | |
printf("Compiling shader : %s\n", fragmentPath); | |
char const * FragmentSourcePointer = FragmentShaderCode.c_str(); | |
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); | |
glCompileShader(FragmentShaderID); | |
// Check Fragment Shader | |
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); | |
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); | |
if ( InfoLogLength > 0 ){ | |
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1); | |
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); | |
printf("%s\n", &FragmentShaderErrorMessage[0]); | |
} | |
// Link the program | |
printf("Linking program\n"); | |
GLuint ProgramID = glCreateProgram(); | |
glAttachShader(ProgramID, VertexShaderID); | |
glAttachShader(ProgramID, FragmentShaderID); | |
glLinkProgram(ProgramID); | |
// Check the program | |
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); | |
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); | |
if ( InfoLogLength > 0 ){ | |
std::vector<char> ProgramErrorMessage(InfoLogLength+1); | |
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); | |
printf("%s\n", &ProgramErrorMessage[0]); | |
} | |
glDetachShader(ProgramID, VertexShaderID); | |
glDetachShader(ProgramID, FragmentShaderID); | |
glDeleteShader(VertexShaderID); | |
glDeleteShader(FragmentShaderID); | |
return ProgramID; | |
} | |
GLFWwindow* createWindow(uint32_t w, uint32_t h, const char title[]) { | |
// Initialise GLFW | |
if( !glfwInit() ) { | |
throw "Failed to initialize GLFW"; | |
} | |
glfwWindowHint(GLFW_SAMPLES, 4); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); | |
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed | |
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
// Open a window and create its OpenGL context | |
GLFWwindow* win = glfwCreateWindow(w, h, title, nullptr, nullptr); | |
if (win == nullptr) { | |
glfwTerminate(); | |
throw "Failed to open GLFW window"; | |
} | |
glfwMakeContextCurrent(win); // create OpenGL context | |
// Initialize GLEW | |
glewExperimental = true; // Needed for core profile | |
if (glewInit() != GLEW_OK) { | |
throw "Failed to initialize GLEW"; | |
} | |
// Ensure we can capture the escape key to quit | |
glfwSetInputMode(win, GLFW_STICKY_KEYS, GL_TRUE); | |
return win; | |
} | |
/* | |
standardized main to catch errors. | |
In this simplified version each error is just reported as a string | |
It would be better to also track which file and line number the error | |
happened in, but that would take an exception object. | |
For now, keeping it simple | |
*/ | |
int main(int argc, char* argv[]) { | |
try { | |
glmain(); | |
glfwTerminate(); // Close OpenGL window and terminate GLFW | |
} catch (const char* msg) { | |
cerr << msg << '\n'; | |
exit(-1); | |
} | |
return 0; | |
} | |
void dump(glm::mat4& mat) { | |
// TODO: I suspect we are printing the matrix transposed | |
const float* m = &mat[0][0]; | |
cerr << setprecision(7); | |
for (int i = 0, c = 0; i < 4; i++) { | |
for (int j = 0; j < 4; j++, c++) | |
cerr << setw(14) << m[c]; | |
cerr << '\n'; | |
} | |
} | |
void transpt(glm::mat4& m, double x, double y, double z) { | |
cerr << "orig=(" << x << "," << y << "," << z << ") transformed: (" << | |
(m[0][0] * x + m[1][0] * y + m[2][0] * z + m[3][0]) << "," << | |
(m[0][1] * x + m[1][1] * y + m[2][1] * z + m[3][1]) << "," << | |
(m[0][2] * x + m[1][2] * y + m[2][2] * z + m[3][2]) << ")\t("; | |
cerr << | |
(m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3]) << "," << | |
(m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3]) << "," << | |
(m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3]) << ")\n"; | |
} | |
GLuint loadWebPTexture(const char* filePath) { | |
// Read the file into a buffer | |
std::ifstream file(filePath, std::ios::binary | std::ios::ate); | |
if (!file.is_open()) { | |
std::cerr << "Failed to open WebP file: " << filePath << std::endl; | |
return 0; | |
} | |
std::streamsize size = file.tellg(); | |
file.seekg(0, std::ios::beg); | |
std::vector<char> buffer(size); | |
if (!file.read(buffer.data(), size)) { | |
std::cerr << "Failed to read WebP file: " << filePath << std::endl; | |
return 0; | |
} | |
// Decode the WebP image | |
int width, height; | |
uint8_t* data = WebPDecodeRGBA(reinterpret_cast<uint8_t*>(buffer.data()), size, &width, &height); | |
if (!data) { | |
std::cerr << "Failed to decode WebP image: " << filePath << std::endl; | |
return 0; | |
} | |
// Generate and bind a texture | |
GLuint textureID; | |
glGenTextures(1, &textureID); | |
glBindTexture(GL_TEXTURE_2D, textureID); | |
// Upload the texture data | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); | |
// Set texture parameters | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
// Free the image data | |
WebPFree(data); | |
return textureID; | |
} |
This file contains hidden or 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
#include <GL/glew.h> // OpenGL API | |
#include <GLFW/glfw3.h> // Window API | |
#include <glm/glm.hpp> // Matrix and vector math for OpenGL | |
#include <glm/ext.hpp> | |
// all demos use a window, declared globally in common.cc | |
extern GLFWwindow* win; | |
GLFWwindow* createWindow(uint32_t w, uint32_t h, const char title[]); | |
GLuint loadShaders(const char vertexPath[], const char * fragmentPath); | |
// the signature of the function to write, automatically called by main | |
void glmain(); | |
/* | |
we provide a standardized main, because it's always the same | |
It catches exceptions and quits if there is a problem | |
you write glmain instead | |
*/ | |
int main(int argc, char* argv[]); | |
void dump(glm::mat4& mat); | |
void transpt(glm::mat4& m, double x, double y, double z); | |
GLuint loadWebPTexture(const char* filePath); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment