Initial commit

This commit is contained in:
Martin Felis
2021-11-11 21:22:24 +01:00
commit b78045ffe7
812 changed files with 421882 additions and 0 deletions
+133
View File
@@ -0,0 +1,133 @@
#pragma once
/*
Quick'n'dirty Maya-style camera. Include after HandmadeMath.h
and sokol_app.h
*/
#include <string.h>
#include <math.h>
#define CAMERA_DEFAULT_MIN_DIST (2.0f)
#define CAMERA_DEFAULT_MAX_DIST (30.0f)
#define CAMERA_DEFAULT_MIN_LAT (-85.0f)
#define CAMERA_DEFAULT_MAX_LAT (85.0f)
#define CAMERA_DEFAULT_DIST (5.0f)
#define CAMERA_DEFAULT_ASPECT (60.0f)
#define CAMERA_DEFAULT_NEARZ (0.01f)
#define CAMERA_DEFAULT_FARZ (100.0f)
typedef struct {
float min_dist;
float max_dist;
float min_lat;
float max_lat;
float distance;
float latitude;
float longitude;
float aspect;
float nearz;
float farz;
hmm_vec3 center;
} camera_desc_t;
typedef struct {
float min_dist;
float max_dist;
float min_lat;
float max_lat;
float distance;
float latitude;
float longitude;
float aspect;
float nearz;
float farz;
hmm_vec3 center;
hmm_vec3 eye_pos;
hmm_mat4 view;
hmm_mat4 proj;
hmm_mat4 view_proj;
} camera_t;
static float _cam_def(float val, float def) {
return ((val == 0.0f) ? def:val);
}
/* initialize to default parameters */
static void cam_init(camera_t* cam, const camera_desc_t* desc) {
assert(cam && desc);
memset(cam, 0, sizeof(camera_t));
cam->min_dist = _cam_def(desc->min_dist, CAMERA_DEFAULT_MIN_DIST);
cam->max_dist = _cam_def(desc->max_dist, CAMERA_DEFAULT_MAX_DIST);
cam->min_lat = _cam_def(desc->min_lat, CAMERA_DEFAULT_MIN_LAT);
cam->max_lat = _cam_def(desc->max_lat, CAMERA_DEFAULT_MAX_LAT);
cam->distance = _cam_def(desc->distance, CAMERA_DEFAULT_DIST);
cam->center = desc->center;
cam->latitude = desc->latitude;
cam->longitude = desc->longitude;
cam->aspect = _cam_def(desc->aspect, CAMERA_DEFAULT_ASPECT);
cam->nearz = _cam_def(desc->nearz, CAMERA_DEFAULT_NEARZ);
cam->farz = _cam_def(desc->farz, CAMERA_DEFAULT_FARZ);
}
/* feed mouse movement */
static void cam_orbit(camera_t* cam, float dx, float dy) {
assert(cam);
cam->longitude -= dx;
if (cam->longitude < 0.0f) {
cam->longitude += 360.0f;
}
if (cam->longitude > 360.0f) {
cam->longitude -= 360.0f;
}
cam->latitude = HMM_Clamp(cam->min_lat, cam->latitude + dy, cam->max_lat);
}
/* feed zoom (mouse wheel) input */
static void cam_zoom(camera_t* cam, float d) {
assert(cam);
cam->distance = HMM_Clamp(cam->min_dist, cam->distance + d, cam->max_dist);
}
static hmm_vec3 _cam_euclidean(float latitude, float longitude) {
const float lat = HMM_ToRadians(latitude);
const float lng = HMM_ToRadians(longitude);
return HMM_Vec3(cosf(lat) * sinf(lng), sinf(lat), cosf(lat) * cosf(lng));
}
/* update the view, proj and view_proj matrix */
static void cam_update(camera_t* cam, int fb_width, int fb_height) {
assert(cam);
assert((fb_width > 0) && (fb_height > 0));
const float w = (float) fb_width;
const float h = (float) fb_height;
cam->eye_pos = HMM_AddVec3(cam->center, HMM_MultiplyVec3f(_cam_euclidean(cam->latitude, cam->longitude), cam->distance));
cam->view = HMM_LookAt(cam->eye_pos, cam->center, HMM_Vec3(0.0f, 1.0f, 0.0f));
cam->proj = HMM_Perspective(cam->aspect, w/h, cam->nearz, cam->farz);
cam->view_proj = HMM_MultiplyMat4(cam->proj, cam->view);
}
/* handle sokol-app input events */
//static void cam_handle_event(camera_t* cam, const sapp_event* ev) {
// assert(cam);
// switch (ev->type) {
// case SAPP_EVENTTYPE_MOUSE_DOWN:
// if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) {
// sapp_lock_mouse(true);
// }
// break;
// case SAPP_EVENTTYPE_MOUSE_UP:
// if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) {
// sapp_lock_mouse(false);
// }
// break;
// case SAPP_EVENTTYPE_MOUSE_SCROLL:
// cam_zoom(cam, ev->scroll_y * 0.5f);
// break;
// case SAPP_EVENTTYPE_MOUSE_MOVE:
// if (sapp_mouse_locked()) {
// cam_orbit(cam, ev->mouse_dx * 0.25f, ev->mouse_dy * 0.25f);
// }
// break;
// default:
// break;
// }
//}
+589
View File
@@ -0,0 +1,589 @@
//------------------------------------------------------------------------------
// imgui-glfw
// Demonstrates basic integration with Dear Imgui (without custom
// texture or custom font support).
//------------------------------------------------------------------------------
#include "imgui.h"
#define SOKOL_IMPL
#define SOKOL_GLCORE33
#include "sokol_gfx.h"
#include "sokol_time.h"
#define SOKOL_GL_IMPL
#include "util/sokol_gl.h"
#define GLFW_INCLUDE_NONE
#include <iostream>
#include "GLFW/glfw3.h"
const int Width = 1024;
const int Height = 768;
const int MaxVertices = (1 << 16);
const int MaxIndices = MaxVertices * 3;
uint64_t last_time = 0;
bool show_imgui_demo_window = false;
bool show_another_window = false;
sg_pass_action pass_action;
sg_pipeline pip;
sg_bindings bind;
typedef struct {
ImVec2 disp_size;
} vs_params_t;
static void draw_imgui(ImDrawData*);
#define HANDMADE_MATH_IMPLEMENTATION
#define HANDMADE_MATH_NO_SSE
#include "HandmadeMath.h"
#include "camera.h"
// ozz-animation headers
#include <cmath> // fmodf
#include <memory> // std::unique_ptr, std::make_unique
#include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/local_to_model_job.h"
#include "ozz/animation/runtime/sampling_job.h"
#include "ozz/animation/runtime/skeleton.h"
#include "ozz/base/containers/vector.h"
#include "ozz/base/io/archive.h"
#include "ozz/base/io/stream.h"
#include "ozz/base/log.h"
#include "ozz/base/maths/soa_transform.h"
#include "ozz/base/maths/vec_float.h"
// wrapper struct for managed ozz-animation C++ objects, mUST BE DEleted
// before shutdown, otherwise ozz-animation will report a memory leak
typedef struct {
ozz::animation::Skeleton skeleton;
ozz::animation::Animation animation;
ozz::animation::SamplingCache cache;
ozz::vector<ozz::math::SoaTransform> local_matrices;
ozz::vector<ozz::math::Float4x4> model_matrices;
} ozz_t;
static struct {
std::unique_ptr<ozz_t> ozz;
sg_pass_action pass_action;
camera_t camera;
struct {
bool skeleton;
bool animation;
bool failed;
} loaded;
struct {
double frame;
double absolute;
uint64_t laptime;
float factor;
float anim_ratio;
bool anim_ratio_ui_override;
bool paused;
} time;
} state;
// io buffers for skeleton and animation data files, we know the max file size upfront
static uint8_t skel_data_buffer[4 * 1024];
static uint8_t anim_data_buffer[32 * 1024];
static void load_skeleton(void);
static void load_animation(void);
static void eval_animation(void);
static void draw_skeleton(void);
static void draw_ui(void);
// static void skeleton_data_loaded(const sfetch_response_t* response);
// static void animation_data_loaded(const sfetch_response_t* response);
static void frame(void);
int main() {
// window and GL context via GLFW and flextGL
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
GLFWwindow* w = glfwCreateWindow(Width, Height, "Sokol+ImGui+GLFW", 0, 0);
glfwMakeContextCurrent(w);
glfwSwapInterval(1);
// GLFW to ImGui input forwarding
glfwSetMouseButtonCallback(
w,
[](GLFWwindow*, int btn, int action, int /*mods*/) {
if ((btn >= 0) && (btn < 3)) {
ImGui::GetIO().MouseDown[btn] = (action == GLFW_PRESS);
}
});
glfwSetCursorPosCallback(w, [](GLFWwindow*, double pos_x, double pos_y) {
ImGui::GetIO().MousePos.x = float(pos_x);
ImGui::GetIO().MousePos.y = float(pos_y);
});
glfwSetScrollCallback(w, [](GLFWwindow*, double /*pos_x*/, double pos_y) {
ImGui::GetIO().MouseWheel = float(pos_y);
});
glfwSetKeyCallback(
w,
[](GLFWwindow*, int key, int /*scancode*/, int action, int mods) {
ImGuiIO& io = ImGui::GetIO();
if ((key >= 0) && (key < 512)) {
io.KeysDown[key] = (action == GLFW_PRESS) || (action == GLFW_REPEAT);
}
io.KeyCtrl = (0 != (mods & GLFW_MOD_CONTROL));
io.KeyAlt = (0 != (mods & GLFW_MOD_ALT));
io.KeyShift = (0 != (mods & GLFW_MOD_SHIFT));
});
glfwSetCharCallback(w, [](GLFWwindow*, unsigned int codepoint) {
ImGui::GetIO().AddInputCharacter((ImWchar)codepoint);
});
// setup sokol_gfx and sokol_time
stm_setup();
sg_desc desc = {};
sg_setup(&desc);
assert(sg_isvalid());
// setup sokol-gl
sgl_desc_t sgldesc = {};
sgldesc.sample_count = 0;
sgl_setup(&sgldesc);
state.ozz = std::make_unique<ozz_t>();
state.time.factor = 1.0f;
// initialize camera helper
camera_desc_t camdesc = {};
camdesc.min_dist = 1.0f;
camdesc.max_dist = 100.0f;
camdesc.farz = 1000.0f;
camdesc.center.Y = 1.0f;
camdesc.distance = 30.0f;
camdesc.latitude = 10.0f;
camdesc.longitude = 20.0f;
cam_init(&state.camera, &camdesc);
// setup Dear Imgui
ImGui::CreateContext();
ImGui::StyleColorsDark();
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = nullptr;
io.Fonts->AddFontDefault();
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
// dynamic vertex- and index-buffers for imgui-generated geometry
sg_buffer_desc vbuf_desc = {};
vbuf_desc.usage = SG_USAGE_STREAM;
vbuf_desc.size = MaxVertices * sizeof(ImDrawVert);
bind.vertex_buffers[0] = sg_make_buffer(&vbuf_desc);
sg_buffer_desc ibuf_desc = {};
ibuf_desc.type = SG_BUFFERTYPE_INDEXBUFFER;
ibuf_desc.usage = SG_USAGE_STREAM;
ibuf_desc.size = MaxIndices * sizeof(ImDrawIdx);
bind.index_buffer = sg_make_buffer(&ibuf_desc);
// font texture for imgui's default font
unsigned char* font_pixels;
int font_width, font_height;
io.Fonts->GetTexDataAsRGBA32(&font_pixels, &font_width, &font_height);
sg_image_desc img_desc = {};
img_desc.width = font_width;
img_desc.height = font_height;
img_desc.pixel_format = SG_PIXELFORMAT_RGBA8;
img_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE;
img_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE;
img_desc.data.subimage[0][0] =
sg_range{font_pixels, size_t(font_width * font_height * 4)};
bind.fs_images[0] = sg_make_image(&img_desc);
// shader object for imgui rendering
sg_shader_desc shd_desc = {};
auto& ub = shd_desc.vs.uniform_blocks[0];
ub.size = sizeof(vs_params_t);
ub.uniforms[0].name = "disp_size";
ub.uniforms[0].type = SG_UNIFORMTYPE_FLOAT2;
shd_desc.vs.source =
"#version 330\n"
"uniform vec2 disp_size;\n"
"layout(location=0) in vec2 position;\n"
"layout(location=1) in vec2 texcoord0;\n"
"layout(location=2) in vec4 color0;\n"
"out vec2 uv;\n"
"out vec4 color;\n"
"void main() {\n"
" gl_Position = vec4(((position/disp_size)-0.5)*vec2(2.0,-2.0), 0.5, "
"1.0);\n"
" uv = texcoord0;\n"
" color = color0;\n"
"}\n";
shd_desc.fs.images[0].name = "tex";
shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D;
shd_desc.fs.source =
"#version 330\n"
"uniform sampler2D tex;\n"
"in vec2 uv;\n"
"in vec4 color;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" frag_color = texture(tex, uv) * color;\n"
"}\n";
sg_shader shd = sg_make_shader(&shd_desc);
// pipeline object for imgui rendering
sg_pipeline_desc pip_desc = {};
pip_desc.layout.buffers[0].stride = sizeof(ImDrawVert);
auto& attrs = pip_desc.layout.attrs;
attrs[0].format = SG_VERTEXFORMAT_FLOAT2;
attrs[1].format = SG_VERTEXFORMAT_FLOAT2;
attrs[2].format = SG_VERTEXFORMAT_UBYTE4N;
pip_desc.shader = shd;
pip_desc.index_type = SG_INDEXTYPE_UINT16;
pip_desc.colors[0].blend.enabled = true;
pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA;
pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
pip_desc.colors[0].write_mask = SG_COLORMASK_RGB;
pip = sg_make_pipeline(&pip_desc);
// initial clear color
pass_action.colors[0].action = SG_ACTION_CLEAR;
pass_action.colors[0].value = {0.0f, 0.5f, 0.7f, 1.0f};
load_skeleton();
load_animation();
// draw loop
while (!glfwWindowShouldClose(w)) {
state.time.frame = stm_sec(
stm_round_to_common_refresh_rate(stm_laptime(&state.time.laptime)));
int cur_width, cur_height;
glfwGetFramebufferSize(w, &cur_width, &cur_height);
cam_update(&state.camera, cur_width, cur_height);
// this is standard ImGui demo code
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2(float(cur_width), float(cur_height));
io.DeltaTime = (float)stm_sec(stm_laptime(&last_time));
ImGui::NewFrame();
if (ImGui::BeginMainMenuBar()) {
ImGui::Text("AnimTestbed");
ImGui::Checkbox("ImGui Demo", &show_imgui_demo_window);
ImGui::EndMainMenuBar();
}
frame();
draw_ui();
// 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowDemoWindow()
if (show_imgui_demo_window) {
ImGui::SetNextWindowPos(ImVec2(460, 20), ImGuiCond_FirstUseEver);
ImGui::ShowDemoWindow();
}
ImGui::Begin("Camera");
ImGui::SliderFloat("min_dist", &state.camera.min_dist, 1.0f, 100.f);
ImGui::SliderFloat("max_dist", &state.camera.max_dist, 1.0f, 100.f);
ImGui::SliderFloat("center.Y", &state.camera.center.Y, 1.0f, 100.f);
ImGui::SliderFloat("distance", &state.camera.distance, 1.0f, 1000.f);
ImGui::SliderFloat("latitude", &state.camera.latitude, 1.0f, 100.f);
ImGui::SliderFloat("longitude", &state.camera.longitude, -179.0f, 179.f);
ImGui::End();
// the sokol_gfx draw pass
sg_begin_default_pass(&pass_action, cur_width, cur_height);
sgl_draw();
ImGui::Render();
draw_imgui(ImGui::GetDrawData());
sg_end_pass();
sg_commit();
glfwSwapBuffers(w);
glfwPollEvents();
}
state.ozz = nullptr;
/* cleanup */
ImGui::DestroyContext();
sgl_shutdown();
sg_shutdown();
glfwTerminate();
return 0;
}
bool LoadSkeleton(const char* _filename, ozz::animation::Skeleton* _skeleton) {
assert(_filename && _skeleton);
ozz::log::Out() << "Loading skeleton archive " << _filename << "."
<< std::endl;
ozz::io::File file(_filename, "rb");
if (!file.opened()) {
ozz::log::Err() << "Failed to open skeleton file " << _filename << "."
<< std::endl;
return false;
}
ozz::io::IArchive archive(&file);
if (!archive.TestTag<ozz::animation::Skeleton>()) {
ozz::log::Err() << "Failed to load skeleton instance from file "
<< _filename << "." << std::endl;
return false;
}
// Once the tag is validated, reading cannot fail.
archive >> *_skeleton;
return true;
}
bool LoadAnimation(
const char* _filename,
ozz::animation::Animation* _animation) {
assert(_filename && _animation);
ozz::log::Out() << "Loading animation archive: " << _filename << "."
<< std::endl;
ozz::io::File file(_filename, "rb");
if (!file.opened()) {
ozz::log::Err() << "Failed to open animation file " << _filename << "."
<< std::endl;
return false;
}
ozz::io::IArchive archive(&file);
if (!archive.TestTag<ozz::animation::Animation>()) {
ozz::log::Err() << "Failed to load animation instance from file "
<< _filename << "." << std::endl;
return false;
}
// Once the tag is validated, reading cannot fail.
archive >> *_animation;
return true;
}
static void load_skeleton(void) {
// const char* skeleton_file = "../media/skeleton.ozz";
const char* skeleton_file = "../media/MixamoYBot-skeleton.ozz";
if (!LoadSkeleton(skeleton_file, &state.ozz->skeleton)) {
std::cerr << "Could not load skeleton " << skeleton_file << std::endl;
return;
}
const int num_soa_joints = state.ozz->skeleton.num_soa_joints();
const int num_joints = state.ozz->skeleton.num_joints();
state.ozz->local_matrices.resize(num_soa_joints);
state.ozz->model_matrices.resize(num_joints);
state.ozz->cache.Resize(num_joints);
state.loaded.skeleton = true;
std::cout << "Successfully loaded " << skeleton_file
<< " (soa: " << num_soa_joints << ", joints: " << num_joints << ")"
<< std::endl;
}
static void load_animation(void) {
// const char* anim_file = "../media/animation1.ozz";
const char* anim_file = "../media/RunningSlow-loop.ozz";
if (!LoadAnimation(anim_file, &state.ozz->animation)) {
std::cerr << "Could not load animation " << anim_file << std::endl;
return;
}
state.loaded.animation = true;
std::cout << "Successfully loade " << anim_file << std::endl;
}
static void draw_ui() {
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
ImGui::Begin("Animation");
ImGui::Checkbox("Time override", &state.time.anim_ratio_ui_override);
const float anim_duration = state.ozz->animation.duration();
if (!state.time.anim_ratio_ui_override) {
state.time.anim_ratio =
fmodf((float)state.time.absolute / anim_duration, 1.0f);
}
ImGui::SliderFloat("Time", &state.time.anim_ratio, 0.f, 1.f);
ImGui::Text(
"Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate,
ImGui::GetIO().Framerate);
ImGui::End();
}
static void frame() {
if (state.loaded.animation && state.loaded.skeleton) {
if (!state.time.paused) {
state.time.absolute += state.time.frame * state.time.factor;
}
eval_animation();
draw_skeleton();
}
}
static void eval_animation() {
// convert current time to animation ration (0.0 .. 1.0)
const float anim_duration = state.ozz->animation.duration();
if (!state.time.anim_ratio_ui_override) {
state.time.anim_ratio =
fmodf((float)state.time.absolute / anim_duration, 1.0f);
}
// sample animation
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &state.ozz->animation;
sampling_job.cache = &state.ozz->cache;
sampling_job.ratio = state.time.anim_ratio;
sampling_job.output = make_span(state.ozz->local_matrices);
sampling_job.Run();
// convert joint matrices from local to model space
ozz::animation::LocalToModelJob ltm_job;
ltm_job.skeleton = &state.ozz->skeleton;
ltm_job.input = make_span(state.ozz->local_matrices);
ltm_job.output = make_span(state.ozz->model_matrices);
ltm_job.Run();
}
static void draw_vec(const ozz::math::SimdFloat4& vec) {
sgl_v3f(ozz::math::GetX(vec), ozz::math::GetY(vec), ozz::math::GetZ(vec));
}
static void draw_line(
const ozz::math::SimdFloat4& v0,
const ozz::math::SimdFloat4& v1) {
draw_vec(v0);
draw_vec(v1);
}
// this draws a wireframe 3d rhombus between the current and parent joints
static void draw_joint(int joint_index, int parent_joint_index) {
if (parent_joint_index < 0) {
return;
}
using namespace ozz::math;
const Float4x4& m0 = state.ozz->model_matrices[joint_index];
const Float4x4& m1 = state.ozz->model_matrices[parent_joint_index];
const SimdFloat4 p0 = m0.cols[3];
const SimdFloat4 p1 = m1.cols[3];
const SimdFloat4 ny = m1.cols[1];
const SimdFloat4 nz = m1.cols[2];
const SimdFloat4 len = SplatX(Length3(p1 - p0)) * simd_float4::Load1(0.1f);
const SimdFloat4 pmid = p0 + (p1 - p0) * simd_float4::Load1(0.66f);
const SimdFloat4 p2 = pmid + ny * len;
const SimdFloat4 p3 = pmid + nz * len;
const SimdFloat4 p4 = pmid - ny * len;
const SimdFloat4 p5 = pmid - nz * len;
sgl_c3f(1.0f, 1.0f, 0.0f);
draw_line(p0, p2);
draw_line(p0, p3);
draw_line(p0, p4);
draw_line(p0, p5);
draw_line(p1, p2);
draw_line(p1, p3);
draw_line(p1, p4);
draw_line(p1, p5);
draw_line(p2, p3);
draw_line(p3, p4);
draw_line(p4, p5);
draw_line(p5, p2);
}
static void draw_skeleton(void) {
sgl_defaults();
sgl_matrix_mode_projection();
sgl_load_matrix((const float*)&state.camera.proj);
sgl_matrix_mode_modelview();
hmm_mat4 scale_mat = HMM_Scale (HMM_Vec3(0.1f, 0.1f, 0.1f));
sgl_load_matrix((const float*)&state.camera.view);
sgl_mult_matrix((const float*)&scale_mat);
const int num_joints = state.ozz->skeleton.num_joints();
ozz::span<const int16_t> joint_parents = state.ozz->skeleton.joint_parents();
sgl_begin_lines();
for (int joint_index = 0; joint_index < num_joints; joint_index++) {
draw_joint(joint_index, joint_parents[joint_index]);
}
sgl_end();
}
// draw ImGui draw lists via sokol-gfx
void draw_imgui(ImDrawData* draw_data) {
assert(draw_data);
if (draw_data->CmdListsCount == 0) {
return;
}
// render the command list
sg_apply_pipeline(pip);
vs_params_t vs_params;
vs_params.disp_size.x = ImGui::GetIO().DisplaySize.x;
vs_params.disp_size.y = ImGui::GetIO().DisplaySize.y;
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE(vs_params));
for (int cl_index = 0; cl_index < draw_data->CmdListsCount; cl_index++) {
const ImDrawList* cl = draw_data->CmdLists[cl_index];
// append vertices and indices to buffers, record start offsets in resource binding struct
const uint32_t vtx_size = cl->VtxBuffer.size() * sizeof(ImDrawVert);
const uint32_t idx_size = cl->IdxBuffer.size() * sizeof(ImDrawIdx);
const uint32_t vb_offset = sg_append_buffer(
bind.vertex_buffers[0],
{&cl->VtxBuffer.front(), vtx_size});
const uint32_t ib_offset =
sg_append_buffer(bind.index_buffer, {&cl->IdxBuffer.front(), idx_size});
/* don't render anything if the buffer is in overflow state (this is also
checked internally in sokol_gfx, draw calls that attempt from
overflowed buffers will be silently dropped)
*/
if (sg_query_buffer_overflow(bind.vertex_buffers[0])
|| sg_query_buffer_overflow(bind.index_buffer)) {
continue;
}
bind.vertex_buffer_offsets[0] = vb_offset;
bind.index_buffer_offset = ib_offset;
sg_apply_bindings(&bind);
int base_element = 0;
for (const ImDrawCmd& pcmd : cl->CmdBuffer) {
if (pcmd.UserCallback) {
pcmd.UserCallback(cl, &pcmd);
} else {
const int scissor_x = (int)(pcmd.ClipRect.x);
const int scissor_y = (int)(pcmd.ClipRect.y);
const int scissor_w = (int)(pcmd.ClipRect.z - pcmd.ClipRect.x);
const int scissor_h = (int)(pcmd.ClipRect.w - pcmd.ClipRect.y);
sg_apply_scissor_rect(scissor_x, scissor_y, scissor_w, scissor_h, true);
sg_draw(base_element, pcmd.ElemCount, 1);
}
base_element += pcmd.ElemCount;
}
}
}
+170
View File
@@ -0,0 +1,170 @@
//========================================================================
// OpenGL triangle example
// Copyright (c) Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
//! [code]
#include <glad/gl.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include "linmath.h"
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
typedef struct Vertex
{
vec2 pos;
vec3 col;
} Vertex;
static const Vertex vertices[3] =
{
{ { -0.6f, -0.4f }, { 1.f, 0.f, 0.f } },
{ { 0.6f, -0.4f }, { 0.f, 1.f, 0.f } },
{ { 0.f, 0.6f }, { 0.f, 0.f, 1.f } }
};
static const char* vertex_shader_text =
"#version 330\n"
"uniform mat4 MVP;\n"
"in vec3 vCol;\n"
"in vec2 vPos;\n"
"out vec3 color;\n"
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
" color = vCol;\n"
"}\n";
static const char* fragment_shader_text =
"#version 330\n"
"in vec3 color;\n"
"out vec4 fragment;\n"
"void main()\n"
"{\n"
" fragment = vec4(color, 1.0);\n"
"}\n";
static void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
int main(void)
{
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(640, 480, "OpenGL Triangle", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetKeyCallback(window, key_callback);
glfwMakeContextCurrent(window);
gladLoadGL(glfwGetProcAddress);
glfwSwapInterval(1);
// NOTE: OpenGL error checks have been omitted for brevity
GLuint vertex_buffer;
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
const GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
glCompileShader(vertex_shader);
const GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
glCompileShader(fragment_shader);
const GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
const GLint mvp_location = glGetUniformLocation(program, "MVP");
const GLint vpos_location = glGetAttribLocation(program, "vPos");
const GLint vcol_location = glGetAttribLocation(program, "vCol");
GLuint vertex_array;
glGenVertexArrays(1, &vertex_array);
glBindVertexArray(vertex_array);
glEnableVertexAttribArray(vpos_location);
glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (void*) offsetof(Vertex, pos));
glEnableVertexAttribArray(vcol_location);
glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (void*) offsetof(Vertex, col));
while (!glfwWindowShouldClose(window))
{
int width, height;
glfwGetFramebufferSize(window, &width, &height);
const float ratio = width / (float) height;
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
mat4x4 m, p, mvp;
mat4x4_identity(m);
mat4x4_rotate_Z(m, m, (float) glfwGetTime());
mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
mat4x4_mul(mvp, p, m);
glUseProgram(program);
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) &mvp);
glBindVertexArray(vertex_array);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
//! [code]