feat: gitea generic artifact repo

This commit is contained in:
anjingyu 2025-07-23 11:56:51 +08:00
parent 033e6df50b
commit 0e46cc5f89
5 changed files with 491 additions and 35 deletions

View File

@ -21,4 +21,4 @@
# Copyright (C) 2021- donkey <anjingyu_ws@foxmail.com>
__author__ = ['"donkey" <anjingyu_ws@foxmail.com>']
__version__ = "0.5.54"
__version__ = "0.6.0"

View File

@ -39,7 +39,7 @@ from .adutil import (
Logger,
AdMakeHelper,
AdGitHelper,
NexusHelper,
ArtifactHelper,
LibMerger,
W,
E,
@ -55,7 +55,6 @@ __author__ = ['"donkey" <anjingyu_ws@foxmail.com>']
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
DEFAULT_BUILD_ROOT = ".build"
DEFAULT_ADMAKE_NAME = ".admake"
DEFAULT_MODULE_GROUP = "ns-module"
DEFAULT_THIRDPARTY_NAME = "3rd-party"
DEFAULT_VERSION_NAME = "master"
SUPPORTED_OS = admakeos.get()
@ -450,8 +449,16 @@ def generate_version_info_file(args, other_args):
return file_path
def default_pkg_owner() -> str:
# For Nexus3: the <repo>/<group>
# For Gitea: the <owner>
if os.getenv("ADMAKE_PACKAGE_OWNER", ""):
return os.getenv("ADMAKE_PACKAGE_OWNER")
return ""
def publish(args, other_args):
nh = NexusHelper()
nh = ArtifactHelper()
# Create or update the version information
with AdUtil.chdir(args.dir):
version_file = generate_version_info_file(args, other_args)
@ -461,10 +468,22 @@ def publish(args, other_args):
dir_list = [los, DEFAULT_THIRDPARTY_NAME, "cmake"]
file_list = ["README.md", "RELEASE.md", version_file]
pkg_dir = os.path.basename(args.dir)
pkg_name = pkg_dir
module_name = f"{pkg_dir}-{args.os}-{args.platform}-{args.pver}.tar.gz"
files = []
subrepo = ""
if not args.owner:
subrepo = default_pkg_owner()
else:
subrepo = args.owner
if not subrepo:
E("Could not retrieve the default owner from environment variable (ADMAKE_PACKAGE_OWNER) or command line argument. Did you use the correct command? The --owner parameter is required to specify the package owner or leave it empty")
return -1
if args.pver != DEFAULT_VERSION_NAME:
# The path in package
pkg_dir = os.path.join(pkg_dir, args.pver)
if args.udf:
@ -530,7 +549,7 @@ def publish(args, other_args):
)
# Send to the server via HTTP POST
r = nh.upload(DEFAULT_MODULE_GROUP, args.location, tar_file)
r = nh.upload(subrepo, pkg_name, args.pver, tar_file)
if r:
fstat = os.stat(tar_file)
@ -577,9 +596,19 @@ def fetch(args, other_args):
if not other_args:
return 0
nh = NexusHelper()
nh = ArtifactHelper()
r = True
subrepo = ""
if not args.owner:
subrepo = default_pkg_owner()
else:
subrepo = args.owner
if not subrepo:
E("Could not retrieve the default owner from environment variable (ADMAKE_PACKAGE_OWNER) or command line argument. Did you use the correct command? The --owner parameter is required to specify the package owner or leave it empty")
return -1
# name convention: <pkg>-<os>-<arch>-<ver>.tar.gz
for p in other_args:
dpath = os.path.join(AdUtil.home(), DEFAULT_ADMAKE_NAME, args.location)
@ -610,7 +639,7 @@ def fetch(args, other_args):
print("Fetching package {} {} ...".format(crayons.green(p), version_info))
r = nh.fetch(
DEFAULT_MODULE_GROUP, args.location, pkg_name, os.path.join(dpath, pkg_name)
subrepo, p, args.pver, pkg_name, os.path.join(dpath, pkg_name)
)
if os.path.isdir(tmp_dir):
@ -948,7 +977,7 @@ def config(args, other_args):
if args.all:
print(crayons.cyan("----------------------------------------"))
# Environment variables
envs = ["ADMAKE_WS_DIR", "NEXUS_HOST", "NEXUS_USERNAME", "NEXUS_PASSWORD"]
envs = ["ADMAKE_WS_DIR", "ADMAKE_PACKAGE_OWNER", "GITEA_HOST", "GITEA_USERNAME", "GITEA_PASSWORD", "GITEA_TOKEN", "NEXUS_HOST", "NEXUS_USERNAME", "NEXUS_PASSWORD"]
print(crayons.yellow("[Environment Variables]"))
for e in envs:
print(f"{e}:", os.getenv(e, ""))
@ -1158,6 +1187,14 @@ def get_admake_arg_parser(extend_parser=None):
help="Specify the version of specified packages, default: master",
)
# For publish and fetch
if c[0] in ["publish", 'fetch']:
sub_parser.add_argument(
"--owner",
default="",
help="Specify the owner of the package, usually, it is the subgroup on remote server.",
)
# for run command
if c[0] in ["run", "test", "bench"]:
sub_parser.add_argument(

View File

@ -42,7 +42,7 @@ import requests
from requests.auth import HTTPBasicAuth
__all__ = ["AdUtil", "AdGitHelper", "AdMakeHelper", "WindowsToolchainHelper"]
__all__ = ["AdUtil", "AdGitHelper", "AdMakeHelper", "ArtifactHelper", "WindowsToolchainHelper"]
__author__ = ['"donkey" <anjingyu_ws@foxmail.com>']
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
@ -414,13 +414,30 @@ class AdUtil:
return default_job_count
class NexusHelper:
# Support Nexus RAW Repo and Gitea Generic Repo
class ArtifactHelper:
# Here support two sets of APIs:
# 1. Nexus3 RAW Repo:
# NEXUS_HOST = "http://172.25.40.12:8088"
# NEXUS_USERNAME = "anonymous"
# NEXUS_PASSWORD = "anonymous"
#
# 2. Gitea Generic Repo:
# GITEA_HOST = "https://gitea.my.com:3443"
# GITEA_USERNAME = "anonymous"
# GITEA_PASSWORD = "anonymous"
# GITEA_TOKEN = "my_token_str"
def __init__(self, host: str = "", auth_info: tuple = ()):
self._host = host
self._token = ""
self._repo_type = "NEXUS"
if not self._host:
if os.getenv("NEXUS_HOST", None):
self._host = os.getenv("NEXUS_HOST")
elif os.getenv("GITEA_HOST", None):
self._host = os.getenv("GITEA_HOST")
self._repo_type = "GITEA"
else:
raise Exception(
"Missing Required Arguments: One of host and NEXUS_HOST must be set!"
@ -428,26 +445,64 @@ class NexusHelper:
self._host = self._host[:-1] if self._host.endswith("/") else self._host
if auth_info and len(auth_info) == 2:
self._auth_info = HTTPBasicAuth(auth_info[0], auth_info[1])
if auth_info:
if len(auth_info) == 2:
self._auth_info = HTTPBasicAuth(auth_info[0], auth_info[1])
elif self._repo_type == "GITEA" and len(auth_info) == 1:
# Gitea token
self._token = f"token {auth_info[0]}"
# Load user and password from environment variables if they exist
elif os.getenv("NEXUS_USERNAME", "") and os.getenv("NEXUS_PASSWORD", ""):
self._auth_info = HTTPBasicAuth(
os.getenv("NEXUS_USERNAME"), os.getenv("NEXUS_PASSWORD")
)
else:
self._auth_info = None
W("Please make sure the Nexus3 service can be accessed by anonymous users.")
if self._repo_type == "GITEA" and os.getenv("GITEA_TOKEN", ""):
# Gitea token
t = os.getenv("GITEA_TOKEN", "")
self._token = f"token {t}"
elif os.getenv(f"{self._repo_type}_USERNAME", "") and os.getenv(f"{self._repo_type}_PASSWORD", ""):
self._auth_info = HTTPBasicAuth(
os.getenv(f"{self._repo_type}_USERNAME"), os.getenv(f"{self._repo_type}_PASSWORD")
)
else:
self._auth_info = None
W(f"Please make sure the {self._repo_type} service can be accessed by anonymous users.")
def fetch(self, repo, group, fname, fpath) -> bool:
url = f"{self._host}/repository/{repo}/{group}/{fname}"
def _auth_opt(self) -> dict:
opts = {}
if not self._token:
opts['auth'] = self._auth_info
else:
opts['headers'] = {"Authorization": self._token}
return opts
r = requests.head(url, auth=self._auth_info)
if r.status_code != 200:
W(f"The file {fname} is not exiting!")
return False
def fetch(self, subrepo, pkg_name, ver, fname, fpath) -> bool:
if self._repo_type == "NEXUS":
url = f"{self._host}/repository/{subrepo}/{fname}"
elif self._repo_type == "GITEA":
url = f"{self._host}/api/packages/{subrepo}/generic/{pkg_name}/{ver}/{fname}"
else:
raise RuntimeError(f"Invalid repo type: {self._repo_type}")
r = requests.get(url, auth=self._auth_info, stream=True)
auth_opts = self._auth_opt()
if self._repo_type == "NEXUS":
r = requests.head(url, **auth_opts)
if r.status_code != 200:
W(f"The file {fname}({ver}) is not existing in NEXUS repo!")
return False
elif self._repo_type == "GITEA":
check_url = f"{self._host}/api/v1/packages/{subrepo}/generic/{pkg_name}/{ver}/files"
r = requests.get(check_url, **auth_opts)
if not r.ok:
W(f"The file {fname}({ver}) is not existing in GITEA generic repo, HTTP code: {r.status_code}, {r.text}!")
return False
jobj = r.json()
for item in jobj:
if item['name'] == fname:
break
else:
W(f"Can not find {fname}({ver}) in GITEA generic repo!")
return False
r = requests.get(url, stream=True, **auth_opts)
fpath = os.path.abspath(fpath)
if os.path.isdir(fpath):
@ -479,22 +534,48 @@ class NexusHelper:
return True
def __put_one_file(
self, repo, group, file_path, parent_dir_len, ignore_structure=False
self, subrepo, pkg_name, ver, file_path, parent_dir_len
):
if ignore_structure:
fname = os.path.basename(file_path)
url = f"{self._host}/repository/{repo}/{group}/{fname}"
if self._repo_type == "NEXUS":
if parent_dir_len == 0:
fname = os.path.basename(file_path)
url = f"{self._host}/repository/{subrepo}/{fname}"
else:
fname = file_path[parent_dir_len:].replace("\\", "/")
url = f"{self._host}/repository/{subrepo}/{fname}"
elif self._repo_type == "GITEA":
url = f"{self._host}/api/packages/{subrepo}/generic/{pkg_name}/{ver}/{fname}"
else:
fname = file_path[parent_dir_len:].replace("\\", "/")
url = f"{self._host}/repository/{repo}/{group}/{fname}"
raise RuntimeError(f"Invalid repo type: {self._repo_type}")
auth_opts = self._auth_opt()
try:
r = requests.put(
url,
auth=self._auth_info,
data=open(file_path, "rb").read(),
**auth_opts
)
if not r.ok:
if self._repo_type == "GITEA" and r.status_code == 409:
# The same name exist already, delete the old one
r = requests.delete(
url,
**auth_opts
)
if not r.ok:
E(f"Failed to publish, can not delete the existent old package: {fname}, please check your permission")
return r.ok
# Try again for GITEA
r = requests.put(
url,
data=open(file_path, "rb").read(),
**auth_opts
)
if not r.ok:
E(f"HTTP Status Code: {r.status_code}")
@ -503,7 +584,7 @@ class NexusHelper:
traceback.print_exc()
return False
def upload(self, repo, group, filepath):
def upload(self, subrepo, pkg_name, ver, filepath):
try:
if os.path.isdir(filepath):
one_dir = filepath
@ -516,14 +597,14 @@ class NexusHelper:
for path, _, file_list in os.walk(one_dir):
for file_name in file_list:
if not self.__put_one_file(
repo, group, os.path.join(path, file_name), parent_dir_len
subrepo, pkg_name, ver, os.path.join(path, file_name), parent_dir_len
):
E("Failed to put file: {} to {}".format(file_name, repo))
return False
elif os.path.isfile(filepath):
fp = os.path.abspath(filepath)
if not self.__put_one_file(
repo, group, fp, len(os.path.dirname(fp)) + 1
subrepo, pkg_name, ver, fp, len(os.path.dirname(fp)) + 1
):
E("Failed to put file: {} to {}".format(fp, repo))
return False

View File

@ -47,3 +47,5 @@ git clone --depth 1 https://github.com/smile-zyk/SRenderer.git
git clone --depth 1 https://github.com/Ryan-D-Gast/quill.git
git clone --depth 1 https://github.com/libui-ng/libui-ng.git
git clone --depth 1 https://github.com/pbhogan/Signals.git
git clone --depth 1 https://github.com/Sopiro/Physics.git
git clone --depth 1 https://github.com/erincatto/box2d.git

View File

@ -3,6 +3,342 @@
#if 0
#include "sww/vmath.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <learnopengl/shader_m.h>
#include <learnopengl/camera.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;
// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f;
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
// tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// configure global opengl state
// -----------------------------
glEnable(GL_DEPTH_TEST);
// build and compile our shader zprogram
// ------------------------------------
Shader ourShader("7.4.camera.vs", "7.4.camera.fs");
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
// world space positions of our cubes
glm::vec3 cubePositions[] = {
glm::vec3( 0.0f, 0.0f, 0.0f),
glm::vec3( 2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3( 2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3( 1.3f, -2.0f, -2.5f),
glm::vec3( 1.5f, 2.0f, -2.5f),
glm::vec3( 1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
};
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// texture coord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// load and create a texture
// -------------------------
unsigned int texture1, texture2;
// texture 1
// ---------
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
unsigned char *data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// texture 2
// ---------
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrChannels, 0);
if (data)
{
// note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)
// -------------------------------------------------------------------------------------------
ourShader.use();
ourShader.setInt("texture1", 0);
ourShader.setInt("texture2", 1);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// per-frame time logic
// --------------------
float currentFrame = static_cast<float>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
// input
// -----
processInput(window);
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// bind textures on corresponding texture units
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
// activate shader
ourShader.use();
// pass projection matrix to shader (note that in this case it could change every frame)
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
ourShader.setMat4("projection", projection);
// camera/view transformation
glm::mat4 view = camera.GetViewMatrix();
ourShader.setMat4("view", view);
// render boxes
glBindVertexArray(VAO);
for (unsigned int i = 0; i < 10; i++)
{
// calculate the model matrix for each object and pass it to shader before drawing
glm::mat4 model = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix first
model = glm::translate(model, cubePositions[i]);
float angle = 20.0f * i;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
ourShader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{
float xpos = static_cast<float>(xposIn);
float ypos = static_cast<float>(yposIn);
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
}
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(static_cast<float>(yoffset));
}
struct swwCameraVirtualTable {};
struct swwCamera {