Skip to content

Instantly share code, notes, and snippets.

@realark
Last active April 24, 2024 05:10
Show Gist options
  • Save realark/d88866fa2fe2459f59e53620931ad155 to your computer and use it in GitHub Desktop.
Save realark/d88866fa2fe2459f59e53620931ad155 to your computer and use it in GitHub Desktop.
opengl hello triangle on c++ and common lisp
#include <iostream>
#include <string>
#include <GL/glew.h>
#include <GL/glu.h>
#include <SDL2/SDL.h>
// compile and run:
// rm csdlopengl ; gcc -o csdlopengl ctraingle.cpp -lSDL2 -lGLEW -lstdc++ -lGL && ./csdlopengl
//***************************************************************************
// The Width of the screen
//***************************************************************************
const GLuint SCREEN_WIDTH = 800;
//***************************************************************************
// The height of the screen
//***************************************************************************
const GLuint SCREEN_HEIGHT = 600;
bool success = GL_TRUE;
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}\0";
const GLchar* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
int main(int argc, char *argv[])
{
//***********************************************************************
// Initialize SDL
//***********************************************************************
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cout << "SDL could not initialize!SDL Error :" <<
std::string(SDL_GetError());
return EXIT_FAILURE;
}
else
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
//*******************************************************************
//The window we'll be rendering to
//*******************************************************************
SDL_Window *window = SDL_CreateWindow("Breakout",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
SCREEN_HEIGHT, SDL_WINDOW_SHOWN |
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (window == NULL)
{
std::cout << "Window could not be created!SDL_Error: " <<
std::string(SDL_GetError()) << std::endl;
return EXIT_FAILURE;
}
//*******************************************************************
//OpenGL context
//*******************************************************************
SDL_GLContext context = SDL_GL_CreateContext(window);
//*******************************************************************
// Set the required callback functions
//*******************************************************************
SDL_Event windowEvent;
//*******************************************************************
//Use OpenGL 3.3
//*******************************************************************
//*******************************************************************
// Set this to true so GLEW knows to use a modern approach to
// retrieving function pointers and extensions
//*******************************************************************
glewExperimental = GL_TRUE;
//*******************************************************************
// Initialize GLEW to setup the OpenGL Function pointers
//*******************************************************************
GLenum glewError = glewInit();
if (GLEW_OK != glewError)
{
std::cout << "Failed to initialize GLEW: " <<
glewGetErrorString(glewError) << std::endl;
return EXIT_FAILURE;
}
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//*******************************************************************
// Define the viewport dimensions
//*******************************************************************
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
//*******************************************************************
// Build and compile our shader program
// Vertex shader
//*******************************************************************
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
//*******************************************************************
// Check for compile time errors
//*******************************************************************
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED: " <<
infoLog << std::endl;
}
//*******************************************************************
// Fragment shader
//*******************************************************************
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
//*******************************************************************
// Check for compile time errors
//*******************************************************************
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED: " <<
infoLog << std::endl;
}
//*******************************************************************
// Link shaders
//*******************************************************************
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
//*******************************************************************
// Check for linking errors
//*******************************************************************
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED: " << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
//*******************************************************************
// Set up vertex data (and buffer(s)) and attribute pointers
//*******************************************************************
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f, // Left
0.5f, -0.5f, 0.0f, // Right
0.0f, 0.5f, 0.0f // Top
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
//*******************************************************************
// Bind the Vertex Array Object first, then bind and set vertex
// buffer(s) and attribute pointer(s).
//*******************************************************************
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat),
(GLvoid*)0);
glEnableVertexAttribArray(0);
//*******************************************************************
// Note that this is allowed, the call to glVertexAttribPointer
// registered VBO as the currently bound vertex buffer object so
// afterwards we can safely unbind
//*******************************************************************
glBindBuffer(GL_ARRAY_BUFFER, 0);
//*******************************************************************
// Unbind VAO (it's always a good thing to unbind any buffer/array to
// prevent strange bugs)
//*******************************************************************
glBindVertexArray(0);
//*******************************************************************
// DeltaTime variables
//*******************************************************************
GLdouble deltaTime = 0.0f;
Uint64 lastFrame = 0L;
Uint64 currentFrame = SDL_GetPerformanceCounter();
while (true)
{
//***************************************************************
// Calculate delta time
//***************************************************************
lastFrame = currentFrame;
currentFrame = SDL_GetPerformanceCounter();
deltaTime = ((currentFrame - lastFrame) * 1000 /
(GLdouble)SDL_GetPerformanceFrequency());
double tmpDeltaTime = deltaTime;
//std::cout << "Hello 1 - deltaTime: " << std::to_string(deltaTime) <<
// std::endl;
if (SDL_PollEvent(&windowEvent))
{
if (windowEvent.type == SDL_QUIT)
{
break;
}
}
//***************************************************************
// Clear the colorbuffer and render
//***************************************************************
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//***************************************************************
// Draw our first triangle
//***************************************************************
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
//***************************************************************
// draw OpenGL: Swap the screen buffers
//***************************************************************
SDL_GL_SwapWindow(window);
}
//***************************************************************
// Properly de-allocate all resources once they've outlived their
// purpose
//***************************************************************
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
SDL_Quit();
}
return EXIT_SUCCESS;
}
(in-package :cl-user)
(require :sdl2)
(require :cl-opengl)
(defvar *gl-triangle* nil)
(defvar *vao* nil)
(defvar *gl-buffer-address* nil)
(defvar *shader-program-id* nil)
(defparameter *vertex-shader-source*
"#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position.x, position.y, position.z, 1.0);
}")
(defparameter *fragment-shader-source*
"#version 330 core
out vec4 color;
void main()
{
color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}")
(defun assert-no-shader-errors (shader-id)
(let ((success (cffi:foreign-alloc :int :initial-element 0)))
(unwind-protect
(progn
(%gl:get-shader-iv shader-id :compile-status success)
(when (/= 1 (cffi:mem-aref success :int))
(error "OpenGl error:~%~A" (gl:get-shader-info-log shader-id))))
(cffi:foreign-free success))))
(defun assert-no-program-errors (program-id)
(let ((success (cffi:foreign-alloc :int :initial-element 0)))
(unwind-protect
(progn
(%gl:get-program-iv program-id :link-status success)
(when (/= 1 (cffi:mem-aref success :int))
(error "OpenGl error:~%~A" (gl:get-program-info-log program-id))))
(cffi:foreign-free success))))
(defun basic-test ()
"The kitchen sink."
(sdl2:with-init (:everything)
(format t "Using SDL Library Version: ~D.~D.~D~%"
sdl2-ffi:+sdl-major-version+
sdl2-ffi:+sdl-minor-version+
sdl2-ffi:+sdl-patchlevel+)
(progn
;; https://wiki.libsdl.org/SDL_GLattr
;; https://wiki.libsdl.org/SDL_GLprofile
(sdl2:gl-set-attr :context-major-version 3)
(sdl2:gl-set-attr :context-minor-version 3)
(sdl2:gl-set-attr :context-profile-mask
sdl2-ffi:+sdl-gl-context-profile-core+)
(sdl2:gl-set-attr :doublebuffer 1)
#+darwin
(sdl2:gl-set-attr :context-forward-compatible-flag
sdl2-ffi:+sdl-gl-context-forward-compatible-flag+))
(sdl2:with-window (win :w 800 :h 600
:flags '(:shown :opengl))
(sdl2:with-gl-context (gl-context win)
(format t "Setting up window/gl.~%")
(progn
(sdl2:gl-make-current win gl-context)
;; https://wiki.libsdl.org/SDL_GL_SetSwapInterval#Remarks
;; first try for adaptive vsync
;; note: using the ffi directly to bypass the rc assertion in wrapper library
(gl:viewport 0 0 800 600)
;; shaders
(let ((vertex-shader (gl:create-shader :vertex-shader))
(fragment-shader (gl:create-shader :fragment-shader)))
(gl:shader-source vertex-shader *vertex-shader-source*)
(gl:compile-shader vertex-shader)
(assert-no-shader-errors vertex-shader)
(gl:shader-source fragment-shader *fragment-shader-source*)
(gl:compile-shader fragment-shader)
(assert-no-shader-errors fragment-shader)
(setf *shader-program-id* (gl:create-program))
(gl:attach-shader *shader-program-id* vertex-shader)
(gl:attach-shader *shader-program-id* fragment-shader)
(gl:link-program *shader-program-id*)
(assert-no-program-errors *shader-program-id*)
(gl:delete-shader vertex-shader)
(gl:delete-shader fragment-shader))
(let ((vec #(-0.5 -0.5 0.0
0.5 -0.5 0.0
0.0 0.5 0.0)))
(setf *gl-triangle*
(loop :with gl-array = (gl:alloc-gl-array :float (length vec))
:for i :from 0 :below (length vec) :do
(setf (gl:glaref gl-array i)
(elt vec i))
:finally (return gl-array))))
(setf *vao* (gl:gen-vertex-array))
(setf *gl-buffer-address* (gl:gen-buffer))
(gl:bind-vertex-array *vao*)
(gl:bind-buffer :array-buffer *gl-buffer-address*)
(gl:buffer-data :array-buffer
:static-draw
*gl-triangle*)
(gl:vertex-attrib-pointer 0 3 :float 0 (* 3 (cffi:foreign-type-size :float)) 0)
(gl:enable-vertex-attrib-array 0)
(gl:bind-buffer :array-buffer 0)
(gl:bind-vertex-array 0))
(gl:clear-color 0.0 1.0 1.0 1.0)
;; main loop
(format t
"Beginning main loop.~% shader-program=~A~% vao=~A~% doublebuffers=~A~%"
*shader-program-id*
*vao*
(sdl2:gl-get-attr :doublebuffer))
(sdl2:with-event-loop (:method :poll)
(:keydown (:keysym keysym)
(let ((scancode (sdl2:scancode-value keysym))
(sym (sdl2:sym-value keysym))
(mod-value (sdl2:mod-value keysym)))
(declare (ignore sym mod-value))
(cond
((sdl2:scancode= scancode :scancode-q) (sdl2:push-event :quit)))))
(:idle ()
(gl:clear :depth-buffer-bit :color-buffer-bit)
(gl:use-program *shader-program-id*)
(gl:bind-vertex-array *vao*)
(gl:draw-arrays :triangles 0 3)
(gl:bind-vertex-array 0)
(sdl2:gl-swap-window win)
(sleep 0.100))
(:quit () t))
(progn
(gl:use-program 0)
(gl:bind-vertex-array 0)
(gl:delete-vertex-arrays (list *vao*))
(setf *vao* nil)
(gl:delete-buffers (list *gl-buffer-address*))
(setf *gl-buffer-address* nil)
(gl:free-gl-array *gl-triangle*)
(setf *gl-triangle* nil)
(gl:delete-program *shader-program-id*)
(setf *shader-program-id* 0))
(format t "Done!~%")))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment