feat: gitea generic artifact repo
This commit is contained in:
parent
033e6df50b
commit
0e46cc5f89
|
@ -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"
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue