Large overhaul, added simple text
This commit is contained in:
parent
4d7084a6de
commit
f2db0dc5e8
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
build/*
|
build/*
|
||||||
assets/*
|
assets/*
|
||||||
bin/*
|
bin/*
|
||||||
|
.cache/*
|
||||||
|
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
*.d
|
*.d
|
||||||
|
2
Makefile
2
Makefile
@ -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
BIN
res/CC.ttf
Normal file
Binary file not shown.
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
//
|
|
||||||
//}
|
|
@ -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
|
|
118
src/gfx/bitmap.c
118
src/gfx/bitmap.c
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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
164
src/gfx/renderer.c
Normal 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
54
src/gfx/renderer.h
Normal 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
|
464
src/main.c
464
src/main.c
@ -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
|
|
||||||
//}
|
|
||||||
|
45
src/main.h
45
src/main.h
@ -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);
|
||||||
|
|
||||||
|
Can't render this file because it is too large.
|
Can't render this file because it is too large.
|
Can't render this file because it is too large.
|
Reference in New Issue
Block a user