Large overhaul, added simple text

This commit is contained in:
Hoguchi-live 2023-01-07 21:02:50 +01:00
parent 4d7084a6de
commit f2db0dc5e8
44 changed files with 543 additions and 577 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
build/* build/*
assets/* assets/*
bin/* bin/*
.cache/*
# Prerequisites # Prerequisites
*.d *.d

View File

@ -18,7 +18,7 @@ OBJEXT := o
CFLAGS := -Wall -pedantic CFLAGS := -Wall -pedantic
CFLAGS += -Ilib/cglm/include -Ilib/glad/include -Ilib/glfw/include -Ilib/stb CFLAGS += -Ilib/cglm/include -Ilib/glad/include -Ilib/glfw/include -Ilib/stb
CFLAGS += -Iinclude/ -I/usr/include/freetype2 -I/usr/include/stb CFLAGS += -Iinclude/ -I/usr/include/freetype2 -I/usr/include/stb
LDFLAGS := -lglfw -ldl -lmpv -lfreetype -lm LDFLAGS := -lglfw -ldl -lmpv -lfreetype -lm
INC := -I$(INCDIR) -I/usr/local/include INC := -I$(INCDIR) -I/usr/local/include
INCDEP := -I$(INCDIR) INCDEP := -I$(INCDIR)

BIN
res/CC.ttf Normal file

Binary file not shown.

View File

@ -7,6 +7,6 @@ uniform mat4 transformation;
void main() void main()
{ {
gl_Position = transformation * vec4(vertex.xy, 0.0, 1.0); gl_Position = vec4(vertex.xy, 0.0, 1.0);
TexCoords = vertex.zw; TexCoords = vertex.zw;
} }

2
run.sh
View File

@ -1 +1 @@
make && ./bin/wotos assets/* ./bin/wotos assets/aa.mkv

View File

@ -1,151 +0,0 @@
#include "danmaku.h"
/// This is so fucking bad, just store everything and redraw with a translation in the shader holy shit
float RenderText(Shader s, std::string text, float x, float y, float scale, glm::vec3 color, uint &VAO, uint &VBO, std::map<char, Character>& Characters, float window_width)
{
// activate corresponding render state
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
s.use();
glUniform3f(glGetUniformLocation(s.ID, "textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
Character ch;
float xpos;
float ypos;
float w;
float h;
// iterate through all characters
std::string::const_iterator c;
for (c = text.begin(); c != text.end(); c++)
{
ch = Characters[*c];
xpos = x + ch.Bearing.x * scale;
ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
w = ch.Size.x * scale;
h = ch.Size.y * scale;
// update VBO for each character
float vertices[6][4] = {
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos, ypos, 0.0f, 1.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos + w, ypos + h, 1.0f, 0.0f }
};
// render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
// update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
// now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.Advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64)
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
return xpos;
}
//TODO: Status <->
/*
Sets nextRow to the index of the next free danmaku row and returns 1 if one is available, returns 0 otherwise.
*/
int getNextDanmakuRow(uint *ph_danmakuRows, int length, uint *nextRow) {
for(int row = 0; row < length; row++) {
if( (ph_danmakuRows)[row] ){
*nextRow = row;
return 1;
}
}
return 0;
}
/*
Flips the status of the danmaku row.
*/
int updateDanmakuRow(uint *ph_danmakuRows, uint row) {
ph_danmakuRows[row] = !ph_danmakuRows[row];
return 0;
}
/*
Updates danmaku array according to the delta between last frame and current frame.
*/
//int updateDanmakus(Render *r){
//
// // Amount of pixels to translate the danmakus by
// float deltaPix = DANMAKU_SPEED*delta;
// // Last glyph x-position (last pixel on the string)
// float lastPix = 0.0f;
//
// // Keep track of danmaku index
// uint danmakuIndex = 0;
//
// for(Danmaku &danmaku : danmakus) {
// if(danmaku.isNew) {
// // Try to assign the new danmaku's row to a free slot
// if(getNextDanmakuRow(ph_danmakuRows, nb_danmakuRows, &(danmaku.row))){
// // Compute the height for that row
// danmaku.ypos = (r->h - DANMAKU_MARGIN_TOP) -
// (danmaku.row + 1) * (DANMAKU_PADDING_V + GLYPH_SIZE);
// danmaku.xpos = r->w;
// // Set the slot to unavailable
// updateDanmakuRow(ph_danmakuRows, danmaku.row);
// danmaku.tailCheck = 0;
// }
// danmaku.isNew = 0;
// }
// else {
// // Translate danmaku
// danmaku.xpos -= deltaPix;
// }
//
// // Draw the danmaku and get tail position
// lastPix = RenderText(r, danmaku.text, danmaku.xpos, danmaku.ypos, 1.0f, glm::vec3(0.0, 0.26f, 0.0f));
// if(lastPix + DANMAKU_PADDING_H < 0) {
// danmakus.erase(danmakus.begin() + danmakuIndex);
// }
//
// // Check if the tail of the danmaku is free (only check once)
// if(!danmaku.tailCheck && (r->w > lastPix + (float)DANMAKU_PADDING_H)) {
// // Free the row slot
// updateDanmakuRow(ph_danmakuRows, danmaku.row);
// danmaku.tailCheck = 1;
// }
// }
// danmakuIndex++;
// }
// return 1;
//}
//OverlayHandler() {
// init();
//}
//
//int OverlayHandler::init() {
// glGenVertexArrays(1, &VAO);
// glGenBuffers(1, &VBO);
// glBindVertexArray(VAO);
// glBindBuffer(GL_ARRAY_BUFFER, VBO);
// glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
// glEnableVertexAttribArray(0);
// glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
// glBindBuffer(GL_ARRAY_BUFFER, 0);
// glBindVertexArray(0);
//
//}

View File

@ -1,65 +0,0 @@
#ifndef _DANMAKU_H_
#define _DANMAKU_H_
#include <shader.h>
#include <map>
#include <vector>
#include "stdlib.h"
#include "stdio.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#define GLYPH_SIZE 36
#define DANMAKU_MARGIN_TOP 50
#define DANMAKU_MARGIN_BOT 50
#define DANMAKU_PADDING_H 200
#define DANMAKU_PADDING_V 20
#define DANMAKU_SPEED_V 200.0f
// Glyphs
typedef struct Character {
unsigned int TextureID; // ID handle of the glyph texture
glm::ivec2 Size; // Size of glyph
glm::ivec2 Bearing; // Offset from baseline to left/top of glyph
long int Advance; // Offset to advance to next glyph
} Character;
// Danmaku
typedef struct Danmaku {
std::string text;
uint isActive;
float xpos;
float ypos;
uint isNew;
uint row;
uint tailCheck;
} Danmaku;
//class OverlayHandler() {
// public:
// OverlayHandler();
//
// float RenderText(Shader, std::string, float, float, float, glm::vec3, uint &, uint &, std::map<char, Character>&);
//
// int init();
//
// private:
// unsigned int VAO, VBO;
//
// void makeBitmaps(std::map<char, Character> &);
//
// Shader *glyphShader = new Shader("shaders/glyph_vs.glsl", "shaders/glyph_fs.glsl");
//
//
//}
int getNextDanmakuRow(uint *, int, uint* );
int updateDanmakuRow(uint *, uint);
int updateDanmakus(Danmaku *, float);
#endif

View File

@ -1,58 +1,64 @@
#include "bitmap.h" #include "bitmap.h"
//void makeBitmaps(std::map<char, Character>& Characters){ CharacterAtlas* makeBitmaps(){
// ///////// FREETYPE2 INIT /////// FREETYPE2 INIT
// FT_Library ft; FT_Library ft;
// if (FT_Init_FreeType(&ft)){ if (FT_Init_FreeType(&ft)){
// std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl; printf("ERROR::FREETYPE: Could not init FreeType Library\n");
// exit(EXIT_FAILURE); exit(EXIT_FAILURE);
// } }
// FT_Face face; FT_Face face;
// if (FT_New_Face(ft, "/usr/share/fonts/TTF/DejaVuSans.ttf", 0, &face)){ if (FT_New_Face(ft, "res/CC.ttf", 0, &face)){
// std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; printf("ERROR::FREETYPE: Failed to load font\n");
// exit(EXIT_FAILURE); exit(EXIT_FAILURE);
// } }
// FT_Set_Pixel_Sizes(face, 0, GLYPH_SIZE); FT_Set_Pixel_Sizes(face, 0, GLYPH_SIZE);
// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction
// glEnable(GL_BLEND); glEnable(GL_BLEND);
//
// CharacterAtlas *atlas = malloc(sizeof(CharacterAtlas));
// for (unsigned char c = 0; c < 128; c++){
// // load character glyph for (unsigned char c = 0; c < 128; c++){
// if (FT_Load_Char(face, c, FT_LOAD_RENDER)){ // load character glyph
// std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; if (FT_Load_Char(face, c, FT_LOAD_RENDER)){
// continue; printf("ERROR::FREETYTPE: Failed to load Glyph\n");
// } continue;
// // generate texture }
// unsigned int texture; // generate texture
// glGenTextures(1, &texture); unsigned int texture;
// glBindTexture(GL_TEXTURE_2D, texture); glGenTextures(1, &texture);
// glTexImage2D( glBindTexture(GL_TEXTURE_2D, texture);
// GL_TEXTURE_2D, glTexImage2D(
// 0, GL_TEXTURE_2D,
// GL_RED, 0,
// face->glyph->bitmap.width, GL_RED,
// face->glyph->bitmap.rows, face->glyph->bitmap.width,
// 0, face->glyph->bitmap.rows,
// GL_RED, 0,
// GL_UNSIGNED_BYTE, GL_RED,
// face->glyph->bitmap.buffer GL_UNSIGNED_BYTE,
// ); face->glyph->bitmap.buffer
// // set texture options );
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // set texture options
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// // now store character for later use glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Character character = { // now store character for later use
// texture, Character character = {
// glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), texture,
// glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), {face->glyph->bitmap.width, face->glyph->bitmap.rows},
// face->glyph->advance.x {face->glyph->bitmap_left, face->glyph->bitmap_top},
// }; face->glyph->advance.x
// Characters.insert(std::pair<char, Character>(c, character)); };
// } atlas->map[c] = character;
// /// Clear glyphs atlas->hashmap[(int)c] = c; // trivial at this point
// FT_Done_Face(face); }
// FT_Done_FreeType(ft); /// Clear glyphs
//} FT_Done_Face(face);
FT_Done_FreeType(ft);
return atlas;
}

View File

@ -1,15 +1,40 @@
#ifndef _BITMAP_H_ #ifndef _BITMAP_H_
#define _BITMAP_H_ #define _BITMAP_H_
#include "gfx.h"
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
//typedef struct Character { #include "stdlib.h"
// unsigned int TextureID; // ID handle of the glyph texture #include "stdio.h"
// glm::ivec2 Size; // Size of glyph
// glm::ivec2 Bearing; // Offset from baseline to left/top of glyph #include "../util/ivec2.h"
// long int Advance; // Offset to advance to next glyph
//} Character; #define GLYPH_SIZE 36
#define DANMAKU_MARGIN_TOP 50
#define DANMAKU_MARGIN_BOT 50
#define DANMAKU_PADDING_H 200
#define DANMAKU_PADDING_V 20
#define DANMAKU_SPEED_V 200.0f
#define MAP_SIZE 128
// Glyphs
typedef struct Character {
unsigned int TextureID; // ID handle of the glyph texture
ivec2 Size; // Size of glyph
ivec2 Bearing; // Offset from baseline to left/top of glyph
long int Advance; // Offset to advance to next glyph
} Character;
typedef struct CharacterAtlas {
Character map[MAP_SIZE];
int size;
int hashmap[MAP_SIZE];
} CharacterAtlas;
CharacterAtlas *makeBitmaps();
#endif #endif

View File

@ -33,8 +33,6 @@ void player_init(struct Player *self) {
mpv_set_wakeup_callback(self->handle, on_mpv_events, NULL); mpv_set_wakeup_callback(self->handle, on_mpv_events, NULL);
mpv_render_context_set_update_callback(self->ctx, on_mpv_render_update, NULL); mpv_render_context_set_update_callback(self->ctx, on_mpv_render_update, NULL);
//const char *cmd[] = {"loadfile", argv[1], NULL};
//mpv_command(mpv, cmd);
mpv_set_option_string(self->handle, "loop", ""); mpv_set_option_string(self->handle, "loop", "");
mpv_set_option_string(self->handle, "gpu-api", "opengl"); mpv_set_option_string(self->handle, "gpu-api", "opengl");
mpv_set_option_string(self->handle, "hwdec", "auto"); mpv_set_option_string(self->handle, "hwdec", "auto");
@ -65,7 +63,7 @@ static void *get_proc_address(void *ctx, const char *name)
static void on_mpv_render_update(void *ctx) static void on_mpv_render_update(void *ctx)
{ {
// we set the wakeup flag here to enable the mpv_render_context_render path in the main loop. // we set the wakeup flag here to enable the mpv_render_context_render path in the main loop.
//wakeup = 1; wakeup = 1;
} }
static void on_mpv_events(void *ctx) static void on_mpv_events(void *ctx)
@ -80,3 +78,8 @@ static inline void check_error(int status)
exit(1); exit(1);
} }
} }
void player_loadfile(struct Player* self, const char *file){
const char *cmd[] = {"loadfile", file, NULL};
mpv_command(self->handle, cmd);
}

View File

@ -8,6 +8,8 @@
#include <mpv/client.h> #include <mpv/client.h>
#include <mpv/render_gl.h> #include <mpv/render_gl.h>
extern int wakeup;
struct Player { struct Player {
mpv_handle *handle; mpv_handle *handle;
mpv_render_context *ctx; mpv_render_context *ctx;
@ -17,4 +19,6 @@ struct Player* player_create();
void player_init(struct Player *self); void player_init(struct Player *self);
void player_destroy(struct Player *self); void player_destroy(struct Player *self);
void player_loadfile(struct Player* self, const char *file);
#endif #endif

164
src/gfx/renderer.c Normal file
View File

@ -0,0 +1,164 @@
#include "renderer.h"
#include "shader.h"
#include "vao.h"
#include "vbo.h"
void _renderer_mpv(struct Renderer *self);
void _renderer_glyph(struct Renderer *self);
float quadVertices[] = {
// positions // texCoords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f , 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f
};
int fbo_width = 1920;
int fbo_height = 1080;
struct Renderer* renderer_create() {
return malloc(sizeof(struct Renderer));
}
void renderer_init(struct Renderer *self) {
self->current_shader = SHADER_NONE;
// Compile shaders
self->shaders[SHADER_MPV] = shader_create(
"res/shaders/screen_vs.glsl", "res/shaders/screen_fs.glsl",
2, (struct VertexAttr[]){
{ .index = 0, .name = "pos" },
{ .index = 1, .name = "texcoord" }
});
self->shaders[SHADER_GLYPH] = shader_create(
"res/shaders/glyph_vs.glsl", "res/shaders/glyph_fs.glsl",
2, (struct VertexAttr[]){
{ .index = 0, .name = "texcoord" }
});
// Define buffers
_renderer_mpv(self);
_renderer_glyph(self);
// Create bitmaps
self->atlas = makeBitmaps();
}
void renderer_destroy(struct Renderer *self) {
for (size_t i = 0; i <= SHADERS_LAST; i++) {
shader_destroy(self->shaders[i]);
}
vao_destroy(self->screenVAO);
vbo_destroy(self->screenVBO);
free(self);
}
/*
Setting up the glyph renderer (for text)
*/
void _renderer_glyph(struct Renderer *self) {
self->glyphVAO = vao_create();
self->glyphVBO = vbo_create(GL_ARRAY_BUFFER, true);
vao_bind(self->glyphVAO);
vbo_bind(self->glyphVBO);
vbo_buffer(self->glyphVBO, &quadVertices, 0, sizeof(float)*6*4);
vao_attr(self->glyphVAO, self->glyphVBO, 0, 4, GL_FLOAT, 4*sizeof(float), 0);
}
/*
Setting up the mpv renderer
*/
void _renderer_mpv(struct Renderer *self) {
/* Screen VAO and VBO */
self->screenVAO = vao_create();
self->screenVBO = vbo_create(GL_ARRAY_BUFFER, false);
vao_bind(self->screenVAO);
vbo_bind(self->screenVBO);
vbo_buffer(self->screenVBO, &quadVertices, 0, sizeof(quadVertices));
vao_attr(self->screenVAO, self->screenVBO, 0, 3, GL_FLOAT, 5*sizeof(float), 0);
vao_attr(self->screenVAO, self->screenVBO, 1, 2, GL_FLOAT, 5*sizeof(float), (3 * sizeof(float)));
/* Framebuffer for Video */
glGenFramebuffers(1, &(self->video_framebuffer));
glBindFramebuffer(GL_FRAMEBUFFER, self->video_framebuffer);
/* create a color attachment texture */
glGenTextures(1, &(self->video_textureColorbuffer));
glBindTexture(GL_TEXTURE_2D, self->video_textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fbo_width, fbo_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->video_textureColorbuffer, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
printf("ERROR::FRAMEBUFFER:: VIDEO Framebuffer #%d is not complete!\n", self->video_framebuffer);
self->mpv_fbo = (mpv_opengl_fbo){(int)(self->video_framebuffer), fbo_width, fbo_height, 0};
}
/*
Render text on the screen using the given Shader
*/
float render_text(struct Renderer *self, const char* text, uint length, float x, float y, float scale, float color[3])
{
shader_bind(self->shaders[SHADER_GLYPH]);
glUniform3f(glGetUniformLocation((self->shaders[SHADER_GLYPH]).handle, "textColor"), color[0], color[1], color[2]);
glActiveTexture(GL_TEXTURE0);
vao_bind(self->glyphVAO);
Character ch;
float xpos;
float ypos;
float w;
float h;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// iterate through all characters
for (unsigned char c = 0; c < length; c++){
ch = self->atlas->map[self->atlas->hashmap[(int)text[c]]];
xpos = x + ch.Bearing[0] * scale;
ypos = y - (ch.Size[1] - ch.Bearing[1]) * scale;
w = ch.Size[0] * scale;
h = ch.Size[1] * scale;
// update VBO for each character
float vertices[6][4] = {
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos, ypos, 0.0f, 1.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos + w, ypos + h, 1.0f, 0.0f }
};
// render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
// update content of VBO memory
vbo_bind(self->glyphVBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
// now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.Advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64)
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
return xpos;
}

54
src/gfx/renderer.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef _RENDERER_H_
#define _RENDERER_H_
#include <mpv/render_gl.h>
#include "shader.h"
#include "vao.h"
#include "vbo.h"
#include "bitmap.h"
#define SHADERS_LAST SHADER_BASIC_COLOR
enum ShaderType {
SHADER_NONE = 0,
SHADER_MPV,
SHADER_GLYPH,
SHADER_BASIC_COLOR,
SHADER_BASIC_TEXTURE
};
struct Renderer{
struct Shader shaders[SHADERS_LAST + 1];
enum ShaderType current_shader;
struct Shader shader;
// TODO: all of these should be more generically defined
struct VBO screenVBO;
struct VAO screenVAO;
unsigned int video_framebuffer;
unsigned int video_textureColorbuffer;
unsigned int screen_framebuffer;
unsigned int screen_textureColorbuffer;
unsigned int screen_rbo;
unsigned int video_rbo;
mpv_opengl_fbo mpv_fbo;
mpv_render_param *params_fbo;
struct VBO glyphVBO;
struct VAO glyphVAO;
CharacterAtlas *atlas;
};
struct Renderer* renderer_create();
void renderer_init(struct Renderer *self);
void renderer_destroy(struct Renderer *self);
float render_text(struct Renderer *self, const char* text, uint length, float x, float y, float scale, float color[3]);
#endif

View File

@ -3,12 +3,214 @@
#include "gfx/vbo.h" #include "gfx/vbo.h"
#include "glad/glad.h" #include "glad/glad.h"
static inline void check_error(int);
int main(int argc, char const *argv[]) int main(int argc, char const *argv[])
{ {
if (argc < 2){ if (argc < 2){
//std::cout << "Usage: " << argv[0] << " videofilename" << std::endl; //std::cout << "Usage: " << argv[0] << " videofilename" << std::endl;
return -1; return -1;
} }
////////// GLFW INIT
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
///////// Create window
if ((wwindow = glfwCreateWindow(window_width, window_height, "a-mpv", NULL, NULL)) == NULL){
printf("ERROR::GLFW::Failed to create window\n");
return -1;
}
glfwMakeContextCurrent(wwindow);
glfwSetFramebufferSizeCallback(wwindow, framebuffer_size_callback);
///////// Load GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
printf("ERROR::GLAD::Failed to initialize GLAD\n");
return -1;
}
//////////// Initializing placeholder for FT text glyphs
//std::map<char, Character> Characters;
//makeBitmaps(Characters);
///////// GL parameters
glEnable(GL_DEPTH);
glEnable(GL_MULTISAMPLE);
glfwWindowHint(GLFW_SAMPLES, 4);
/* Glyph shenanigans
*/
//mat4s transformation = glms_ortho(0.0f, (float)(window_width), 0.0f, (float)window_height, -100, 100);
/* Setting up MPV player
The mpv and mpv_ctx variables are temporary
*/
player = player_create();
player_init(player);
mpv = player->handle;
mpv_ctx = player->ctx;
/* Setting the renderer
The mpv and mpv_ctx variables are temporary
*/
renderer = renderer_create();
renderer_init(renderer);
// this doesn't work when called inside the Renderer struct...
int flip_y = 1;
renderer->params_fbo = (mpv_render_param [3]){
{MPV_RENDER_PARAM_OPENGL_FBO, &(renderer->mpv_fbo)},
{MPV_RENDER_PARAM_FLIP_Y, &flip_y},
{MPV_RENDER_PARAM_INVALID, NULL}};
/*
Start video playback
*/
const char filename[] = "https://stream.wotos.eu/snw_master.m3u8";
player_loadfile(player, filename);
const char *text = "I Joe";
while (!glfwWindowShouldClose(wwindow))
{
fcount++;
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
//if (fcount % 100 == 0){
// std::cout << "FPS: " << 1 / deltaTime << "\n" << std::endl;
// }
processGLFWInput(wwindow, mpv);
// -----
if (wakeup)
{
if ((mpv_render_context_update(mpv_ctx) & MPV_RENDER_UPDATE_FRAME))
{
mpv_render_context_render(mpv_ctx, renderer->params_fbo); // this "renders" to the video_framebuffer "linked by ID" in the params_fbo - BLOCKING
glViewport(0, 0, window_width, window_height); // fucky
}
}
//screenShader->use();
shader_bind(renderer->shaders[SHADER_MPV]);
vao_bind(renderer->screenVAO);
glBindTexture(GL_TEXTURE_2D, renderer->video_textureColorbuffer); // <-- SCREEN Colorbuffer IS THE TEXTURE
glDrawArrays(GL_TRIANGLES, 0, 6);
// -----
if (wakeup)
{
mpv_render_context_report_swap(mpv_ctx);
wakeup = 0;
}
render_text(renderer, text, strlen(text), 0, 0, 0.001, (float [3]){0.0, 1.0, 0.0});
//glUniformMatrix4fv(glGetUniformLocation(renderer->shaders[SHADER_GLYPH].handle, "ransformation"), 1, GL_FALSE, (GLfloat *)&transformation.raw);
//Distance during deltaTime for consistent translation
//// Draw image
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//imgShader->use();
//glBindVertexArray(imgVBO); // <-- The SCREEN QUAD
//glBindTexture(GL_TEXTURE_2D, imgTex); // <-- SCREEN Colorbuffer IS THE TEXTURE
//imgMatrix = glm::translate(imgMatrix, glm::vec3(0.5/deltaPix, 0.0f, 0.0f));
//glUniformMatrix4fv(glGetUniformLocation(imgShader->ID, "transformation"), 1, GL_FALSE, glm::value_ptr(imgMatrix));
//glDrawArrays(GL_TRIANGLES, 0, 6);
// // Glyphs
//transformation = glm::translate(transformation, glm::vec3(deltaPix , 0.0f, 0.0f));
/////////////////////////////////////////// SOCKET
//recv_bytes = recv(sock, buffer, RECV_BUFFER_SIZE, 0);
//if(recv_bytes >= 1){
// danmakus.push_back({buffer, 1, (float)window_width, 400.0f, 1, 0, 0});
//}
//std::cout << danmakus.front().text << std::endl;
/////////////////////////////////////////// Danmaku update
//updateDanmakus(r);
//}
glfwSwapBuffers(wwindow);
glfwPollEvents();
usleep(16 * 1000); // we LIMIT the main render loop to 100FPS! If VSYSNC is enabled the limit is the VSYNC limit (~60fps)
}
renderer_destroy(renderer);
player_destroy(player);
mpv_render_context_free(mpv_ctx);
mpv_terminate_destroy(mpv);
glfwTerminate();
return 0;
}
void processGLFWInput(GLFWwindow *window, mpv_handle *ctx)
{
glfwSetInputMode(window, GLFW_STICKY_KEYS, GLFW_FALSE);
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
const char *c[] = {"show-text", "lol", NULL};
check_error(mpv_command(ctx, c));
}
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
// we have to rescale the Texture and renderbuffer storage.
window_height = height;
window_width = width;
glBindTexture(GL_TEXTURE_2D, renderer->screen_textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindRenderbuffer(GL_RENDERBUFFER, screen_rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, window_width, window_height);
}
static inline void check_error(int status)
{
if (status < 0) {
printf("mpv API error: %s\n", mpv_error_string(status));
//exit(1);
}
}
//
///** Returns true on success, or false if there was an error */
//bool SetSocketBlockingEnabled(int fd, bool blocking)
//{
// if (fd < 0) return false;
//
//#ifdef _WIN32
// unsigned long mode = blocking ? 0 : 1;
// return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false;
//#else
// int flags = fcntl(fd, F_GETFL, 0);
// if (flags == -1) return false;
// flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
// return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
//#endif
//////////// SOCKET SERVER //////////// SOCKET SERVER
//// create socket file descriptor //// create socket file descriptor
//int server_fd; //int server_fd;
@ -45,117 +247,9 @@ int main(int argc, char const *argv[])
// perror("listen failed"); // perror("listen failed");
// exit(EXIT_FAILURE); // exit(EXIT_FAILURE);
//} //}
//}
////////// GLFW INIT //// BUNCH OF CRAP
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
///////// Create window
if ((wwindow = glfwCreateWindow(window_width, window_height, "a-mpv", NULL, NULL)) == NULL){
printf("ERROR::GLFW::Failed to create window\n");
return -1;
}
glfwMakeContextCurrent(wwindow);
glfwSetFramebufferSizeCallback(wwindow, framebuffer_size_callback);
///////// Load GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
printf("ERROR::GLAD::Failed to initialize GLAD\n");
return -1;
}
//////////// Initializing placeholder for FT text glyphs
//std::map<char, Character> Characters;
//makeBitmaps(Characters);
///////// GL parameters
glEnable(GL_DEPTH);
glEnable(GL_MULTISAMPLE);
glfwWindowHint(GLFW_SAMPLES, 4);
///////// MPV INIT
mpv = mpv_create();
if (mpv_initialize(mpv) < MPV_ERROR_SUCCESS){
printf("ERROR::MPV::Failed to initialize mpv\n");
return -1;
}
mpv_opengl_init_params opengl_init_params={get_proc_address, NULL};
int adv = 1; // we will use the update callback
mpv_render_param render_param[] = {
{MPV_RENDER_PARAM_API_TYPE, (char *)(MPV_RENDER_API_TYPE_OPENGL)},
{MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &opengl_init_params},
{MPV_RENDER_PARAM_ADVANCED_CONTROL, &adv},
{MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME, NULL},
{MPV_RENDER_PARAM_INVALID, NULL},
};
if (mpv_render_context_create(&mpv_ctx, mpv, render_param) < MPV_ERROR_SUCCESS){
printf("ERROR::MPV::Failed to create MPV render context\n");
return -1;
}
mpv_set_wakeup_callback(mpv, on_mpv_events, NULL);
mpv_render_context_set_update_callback(mpv_ctx, on_mpv_render_update, NULL);
const char *cmd[] = {"loadfile", argv[1], NULL};
mpv_command(mpv, cmd);
mpv_set_option_string(mpv, "loop", "");
mpv_set_option_string(mpv, "gpu-api", "opengl");
mpv_set_option_string(mpv, "hwdec", "auto");
mpv_set_option_string(mpv, "vd-lavc-dr", "yes");
//mpv_set_option_string(mpv, "terminal", "yes");
// mpv_set_option_string(mpv, "video-timing-offset", "0"); // this need manual fps adjustment mpv_render_frame_info()
check_error(mpv_set_option_string(mpv, "input-default-bindings", "yes"));
mpv_set_option_string(mpv, "input-vo-keyboard", "yes");
int val = 1;
check_error(mpv_set_option(mpv, "osc", MPV_FORMAT_FLAG, &val));
struct Shader screenShader = shader_create(
"res/shaders/screen_vs.glsl", "res/shaders/screen_fs.glsl",
2, (struct VertexAttr[]){
{ .index = 0, .name = "pos" },
{ .index = 1, .name = "texCoords"}
});
//// TEST VAO REPLACE
quadVAOTEST = vao_create();
quadVBOTEST = vbo_create(GL_ARRAY_BUFFER, false);
vao_bind(quadVAOTEST);
vbo_bind(quadVBOTEST);
vbo_buffer(quadVBOTEST, &quadVertices, 0, sizeof(quadVertices));
vao_attr(quadVAOTEST, quadVBOTEST, 0, 3, GL_FLOAT, 5*sizeof(float), 0);
vao_attr(quadVAOTEST, quadVBOTEST, 1, 2, GL_FLOAT, 5*sizeof(float), (3 * sizeof(float)));
//Framebuffer for Video
glGenFramebuffers(1, &video_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, video_framebuffer);
// create a color attachment texture
glGenTextures(1, &video_textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, video_textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fbo_width, fbo_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, video_textureColorbuffer, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
printf("ERROR::FRAMEBUFFER:: VIDEO Framebuffer #%d is not complete!\n", video_framebuffer);
mpv_opengl_fbo mpv_fbo = {(int)(video_framebuffer), fbo_width, fbo_height, 0};
int flip_y = 1;
mpv_render_param params_fbo[] = {
{MPV_RENDER_PARAM_OPENGL_FBO, &mpv_fbo},
{MPV_RENDER_PARAM_FLIP_Y, &flip_y},
{MPV_RENDER_PARAM_INVALID, NULL}};
////////// IMAGE TEST ////////// IMAGE TEST
//// Import image //// Import image
//int imgWidth, imgHeight, imgChan; //int imgWidth, imgHeight, imgChan;
@ -265,153 +359,3 @@ int main(int argc, char const *argv[])
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
while (!glfwWindowShouldClose(wwindow))
{
fcount++;
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
//if (fcount % 100 == 0){
// std::cout << "FPS: " << 1 / deltaTime << "\n" << std::endl;
// }
processGLFWInput(wwindow, mpv);
// -----
if (wakeup)
{
if ((mpv_render_context_update(mpv_ctx) & MPV_RENDER_UPDATE_FRAME))
{
mpv_render_context_render(mpv_ctx, params_fbo); // this "renders" to the video_framebuffer "linked by ID" in the params_fbo - BLOCKING
glViewport(0, 0, window_width, window_height); // fucky
}
}
//screenShader->use();
shader_bind(screenShader);
//glBindVertexArray(quadVBO); // <-- The SCREEN QUAD
vao_bind(quadVAOTEST);
glBindTexture(GL_TEXTURE_2D, video_textureColorbuffer); // <-- SCREEN Colorbuffer IS THE TEXTURE
glDrawArrays(GL_TRIANGLES, 0, 6);
// -----
if (wakeup)
{
mpv_render_context_report_swap(mpv_ctx);
wakeup = 0;
}
//Distance during deltaTime for consistent translation
//// Draw image
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//imgShader->use();
//glBindVertexArray(imgVBO); // <-- The SCREEN QUAD
//glBindTexture(GL_TEXTURE_2D, imgTex); // <-- SCREEN Colorbuffer IS THE TEXTURE
//imgMatrix = glm::translate(imgMatrix, glm::vec3(0.5/deltaPix, 0.0f, 0.0f));
//glUniformMatrix4fv(glGetUniformLocation(imgShader->ID, "transformation"), 1, GL_FALSE, glm::value_ptr(imgMatrix));
//glDrawArrays(GL_TRIANGLES, 0, 6);
// // Glyphs
//transformation = glm::translate(transformation, glm::vec3(deltaPix , 0.0f, 0.0f));
//glyphShader->use();
//// TEMPORARY
//glUniformMatrix4fv(glGetUniformLocation(glyphShader->ID, "transformation"), 1, GL_FALSE, glm::value_ptr(transformation));
/////////////////////////////////////////// SOCKET
//recv_bytes = recv(sock, buffer, RECV_BUFFER_SIZE, 0);
//if(recv_bytes >= 1){
// danmakus.push_back({buffer, 1, (float)window_width, 400.0f, 1, 0, 0});
//}
//std::cout << danmakus.front().text << std::endl;
/////////////////////////////////////////// Danmaku update
//updateDanmakus(r);
//}
glfwSwapBuffers(wwindow);
glfwPollEvents();
//usleep(10000); // we LIMIT the main render loop to 100FPS! If VSYSNC is enabled the limit is the VSYNC limit (~60fps)
}
mpv_render_context_free(mpv_ctx);
mpv_terminate_destroy(mpv);
glfwTerminate();
return 0;
}
void processGLFWInput(GLFWwindow *window, mpv_handle *ctx)
{
glfwSetInputMode(window, GLFW_STICKY_KEYS, GLFW_FALSE);
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
const char *c[] = {"show-text", "lol", NULL};
check_error(mpv_command(ctx, c));
}
}
// Returns the address of the specified function (name) for the given context (ctx)
static void *get_proc_address(void *ctx, const char *name)
{
glfwGetCurrentContext();
return (void *)(glfwGetProcAddress(name));
}
static void on_mpv_render_update(void *ctx)
{
// we set the wakeup flag here to enable the mpv_render_context_render path in the main loop.
wakeup = 1;
}
static void on_mpv_events(void *ctx)
{
//std::cout << "INFO::" << __func__ << std::endl;
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
// we have to rescale the Texture and renderbuffer storage.
window_height = height;
window_width = width;
glBindTexture(GL_TEXTURE_2D, screen_textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindRenderbuffer(GL_RENDERBUFFER, screen_rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, window_width, window_height);
}
static inline void check_error(int status)
{
if (status < 0) {
printf("mpv API error: %s\n", mpv_error_string(status));
//exit(1);
}
}
//
///** Returns true on success, or false if there was an error */
//bool SetSocketBlockingEnabled(int fd, bool blocking)
//{
// if (fd < 0) return false;
//
//#ifdef _WIN32
// unsigned long mode = blocking ? 0 : 1;
// return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false;
//#else
// int flags = fcntl(fd, F_GETFL, 0);
// if (flags == -1) return false;
// flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
// return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
//#endif
//}

View File

@ -9,19 +9,13 @@
#include "gfx/vao.h" #include "gfx/vao.h"
#include "gfx/vbo.h" #include "gfx/vbo.h"
#include "gfx/player.h"
#include "gfx/renderer.h"
//#include "danmaku/danmaku.h"
//#include <cstring>
#include <unistd.h> #include <unistd.h>
#include "gfx/shader.h" #include "gfx/shader.h"
#include "gfx/bitmap.h" #include "gfx/bitmap.h"
//#include "glm/glm.hpp"
//#include <glm/gtc/matrix_transform.hpp>
//#include <glm/gtx/transform.hpp>
//#include <glm/gtc/type_ptr.hpp>
//#include <sys/socket.h> //#include <sys/socket.h>
//#include <sys/types.h> //#include <sys/types.h>
//#include <netdb.h> //#include <netdb.h>
@ -41,23 +35,16 @@
//#define STB_IMAGE_IMPLEMENTATION //#define STB_IMAGE_IMPLEMENTATION
//#include <stb/stb_image.h> //#include <stb/stb_image.h>
int main(int argc, char const *argv[]); int main(int argc, char const *argv[]);
int window_width = 1366; int window_width = 1920;
int window_height = 768; int window_height = 1080;
int fbo_width = 1366;
int fbo_height = 768;
GLFWwindow *wwindow = NULL; GLFWwindow *wwindow = NULL;
mpv_handle *mpv; mpv_handle *mpv;
mpv_render_context *mpv_ctx; mpv_render_context *mpv_ctx;
unsigned int video_framebuffer;
unsigned int video_textureColorbuffer;
unsigned int screen_framebuffer;
unsigned int screen_textureColorbuffer;
unsigned int screen_rbo; unsigned int screen_rbo;
unsigned int video_rbo; unsigned int video_rbo;
unsigned int quadVAO, quadVBO; unsigned int quadVAO, quadVBO;
@ -66,11 +53,14 @@ unsigned int cubeVAO, cubeVBO;
struct VAO quadVAOTEST; struct VAO quadVAOTEST;
struct VBO quadVBOTEST; struct VBO quadVBOTEST;
struct Player *player;
struct Renderer *renderer;
float deltaTime, lastFrame; float deltaTime, lastFrame;
unsigned int fcount = 0; unsigned int fcount = 0;
bool animation=true; bool animation=true;
static void *get_proc_address(void *ctx, const char *name); //static void *get_proc_address(void *ctx, const char *name);
void processGLFWInput(GLFWwindow *window, mpv_handle *); void processGLFWInput(GLFWwindow *window, mpv_handle *);
void framebuffer_size_callback(GLFWwindow *window, int width, int height); void framebuffer_size_callback(GLFWwindow *window, int width, int height);
@ -84,22 +74,13 @@ float imgVertices[] = {
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f}; 1.0f, 1.0f, 0.0f, 1.0f, 1.0f};
float quadVertices[] = {
// positions // texCoords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f , 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, //static void on_mpv_render_update(void *ctx);
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, //static void on_mpv_events(void *ctx);
1.0f, 1.0f, 0.0f, 1.0f, 1.0f};
int wakeup = 0;
extern int wakeup;
static void on_mpv_render_update(void *ctx);
static void on_mpv_events(void *ctx);
unsigned int wakeup = 0;
static inline void check_error(int);
bool SetSocketBlockingEnabled(int fd, bool blocking); bool SetSocketBlockingEnabled(int fd, bool blocking);

View File

Can't render this file because it is too large.

View File

Can't render this file because it is too large.