Remove src-c files that have been ported.
This commit is contained in:
parent
a53b53e864
commit
14b448d8fb
@ -1,91 +0,0 @@
|
|||||||
#include "Font.h"
|
|
||||||
|
|
||||||
#define round_up_26_6(val) (((val) + 63) >> 6u)
|
|
||||||
|
|
||||||
static FT_Library ft_library_handle;
|
|
||||||
static bool ft_initialized;
|
|
||||||
|
|
||||||
bool Initialize_FreeType()
|
|
||||||
{
|
|
||||||
if (ft_initialized)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FT_Init_FreeType(&ft_library_handle) != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ft_initialized = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Font::load(const char * fname, int size)
|
|
||||||
{
|
|
||||||
if (!Initialize_FreeType())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FT_New_Face(ft_library_handle, fname, 0, &m_face) != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_Set_Pixel_Sizes(m_face, 0, size);
|
|
||||||
|
|
||||||
return preload_glyphs();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Font::preload_glyphs()
|
|
||||||
{
|
|
||||||
static const char preload_glyph_list[] = "HMgjqxy_|^";
|
|
||||||
|
|
||||||
int max_top = -9999;
|
|
||||||
int min_bottom = 9999;
|
|
||||||
m_advance = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0u; i < sizeof(preload_glyph_list) - 1u; i++)
|
|
||||||
{
|
|
||||||
std::shared_ptr<Glyph> g = get_glyph(preload_glyph_list[i]);
|
|
||||||
if (g == NULL)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (m_face->glyph->bitmap_top > max_top)
|
|
||||||
{
|
|
||||||
max_top = m_face->glyph->bitmap_top;
|
|
||||||
}
|
|
||||||
int bitmap_bottom = m_face->glyph->bitmap_top - m_face->glyph->bitmap.rows;
|
|
||||||
if (bitmap_bottom < min_bottom)
|
|
||||||
{
|
|
||||||
min_bottom = bitmap_bottom;
|
|
||||||
}
|
|
||||||
if (g->get_advance() > m_advance)
|
|
||||||
{
|
|
||||||
m_advance = g->get_advance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_line_height = round_up_26_6(m_face->size->metrics.height);
|
|
||||||
m_baseline_offset = (m_line_height - (max_top - min_bottom)) / 2 - min_bottom;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Glyph> Font::get_glyph(FT_ULong character)
|
|
||||||
{
|
|
||||||
auto it = m_glyphs.find(character);
|
|
||||||
if (it != m_glyphs.end())
|
|
||||||
{
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
std::shared_ptr<Glyph> glyph = std::make_shared<Glyph>();
|
|
||||||
if (!glyph->load(m_face, character))
|
|
||||||
{
|
|
||||||
glyph = nullptr;
|
|
||||||
}
|
|
||||||
m_glyphs[character] = glyph;
|
|
||||||
return glyph;
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
#ifndef FONT_H
|
|
||||||
#define FONT_H
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <memory>
|
|
||||||
#include "Glyph.h"
|
|
||||||
|
|
||||||
class Font
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool load(const char * fname, int size);
|
|
||||||
std::shared_ptr<Glyph> get_glyph(FT_ULong character);
|
|
||||||
int get_advance() { return m_advance; }
|
|
||||||
int get_line_height() { return m_line_height; }
|
|
||||||
int get_baseline_offset() { return m_baseline_offset; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool preload_glyphs();
|
|
||||||
|
|
||||||
FT_Face m_face;
|
|
||||||
std::unordered_map<FT_ULong, std::shared_ptr<Glyph>> m_glyphs;
|
|
||||||
int m_advance;
|
|
||||||
int m_line_height;
|
|
||||||
int m_baseline_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||||||
#include "Glyph.h"
|
|
||||||
|
|
||||||
#define round_up_26_6(val) (((val) + 63) >> 6u)
|
|
||||||
|
|
||||||
bool Glyph::load(FT_Face face, FT_ULong char_code)
|
|
||||||
{
|
|
||||||
if (FT_Load_Char(face, char_code, FT_LOAD_RENDER) != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_texture = glcxx::Texture::create();
|
|
||||||
m_texture->bind(GL_TEXTURE_2D);
|
|
||||||
int width = face->glyph->bitmap.width;
|
|
||||||
int rounded_width = glcxx::Texture::next_power_of_2(width);
|
|
||||||
int height = face->glyph->bitmap.rows;
|
|
||||||
int rounded_height = glcxx::Texture::next_power_of_2(height);
|
|
||||||
m_advance = round_up_26_6(face->glyph->advance.x);
|
|
||||||
uint8_t * texture = new uint8_t[rounded_width * rounded_height];
|
|
||||||
memset(texture, 0, rounded_width * rounded_height);
|
|
||||||
for (int i = 0; i < height; i++)
|
|
||||||
{
|
|
||||||
memcpy(&texture[rounded_width * i],
|
|
||||||
&face->glyph->bitmap.buffer[width * (height - i - 1)],
|
|
||||||
width);
|
|
||||||
}
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, rounded_width, rounded_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texture);
|
|
||||||
delete[] texture;
|
|
||||||
|
|
||||||
m_array = glcxx::Array::create();
|
|
||||||
m_array->bind();
|
|
||||||
|
|
||||||
int left = face->glyph->bitmap_left;
|
|
||||||
int top = face->glyph->bitmap_top;
|
|
||||||
float s_max = width / (float)rounded_width;
|
|
||||||
float t_max = height / (float)rounded_height;
|
|
||||||
m_buffer = glcxx::Buffer::create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, {
|
|
||||||
(GLfloat)left, (GLfloat)(top - height), 0.0, 0.0,
|
|
||||||
(GLfloat)(left + width), (GLfloat)(top - height), s_max, 0.0,
|
|
||||||
(GLfloat)left, (GLfloat)top, 0.0, t_max,
|
|
||||||
(GLfloat)(left + width), (GLfloat)top, s_max, t_max,
|
|
||||||
});
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
#ifndef GLYPH_H
|
|
||||||
#define GLYPH_H
|
|
||||||
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
#include "glcxx.hpp"
|
|
||||||
|
|
||||||
class Glyph
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool load(FT_Face face, FT_ULong char_code);
|
|
||||||
int get_advance() { return m_advance; }
|
|
||||||
void render()
|
|
||||||
{
|
|
||||||
m_array->bind();
|
|
||||||
m_texture->bind(GL_TEXTURE_2D);
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int m_advance;
|
|
||||||
std::shared_ptr<glcxx::Texture> m_texture;
|
|
||||||
std::shared_ptr<glcxx::Buffer> m_buffer;
|
|
||||||
std::shared_ptr<glcxx::Array> m_array;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,44 +0,0 @@
|
|||||||
#ifndef PANE_H
|
|
||||||
#define PANE_H
|
|
||||||
|
|
||||||
class Pane
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Pane()
|
|
||||||
{
|
|
||||||
m_x = 0;
|
|
||||||
m_y = 0;
|
|
||||||
m_width = 0;
|
|
||||||
m_height = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void move(int x, int y)
|
|
||||||
{
|
|
||||||
m_x = x;
|
|
||||||
m_y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void resize(int width, int height)
|
|
||||||
{
|
|
||||||
m_width = width;
|
|
||||||
m_height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
int win_x(int offset)
|
|
||||||
{
|
|
||||||
return m_x + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
int win_y(int offset)
|
|
||||||
{
|
|
||||||
return m_y + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int m_x;
|
|
||||||
int m_y;
|
|
||||||
int m_width;
|
|
||||||
int m_height;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,17 +0,0 @@
|
|||||||
#include "FlatShader.h"
|
|
||||||
#include "Runtime.h"
|
|
||||||
|
|
||||||
FlatShader::FlatShader()
|
|
||||||
{
|
|
||||||
std::string v_path = Runtime::find(Runtime::SHADER, "flat.v");
|
|
||||||
std::string f_path = Runtime::find(Runtime::SHADER, "flat.f");
|
|
||||||
|
|
||||||
m_program = glcxx::Program::create(
|
|
||||||
glcxx::Shader::create_from_file(GL_VERTEX_SHADER, v_path.c_str()),
|
|
||||||
glcxx::Shader::create_from_file(GL_FRAGMENT_SHADER, f_path.c_str()),
|
|
||||||
"coords", 0);
|
|
||||||
|
|
||||||
m_uniforms.viewport_size = m_program->get_uniform_location("viewport_size");
|
|
||||||
m_uniforms.position = m_program->get_uniform_location("position");
|
|
||||||
m_uniforms.color = m_program->get_uniform_location("color");
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
#ifndef FLATSHADER_H
|
|
||||||
#define FLATSHADER_H
|
|
||||||
|
|
||||||
#include "glcxx.hpp"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class FlatShader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FlatShader();
|
|
||||||
|
|
||||||
void use() { m_program->use(); }
|
|
||||||
|
|
||||||
void set_viewport_size(int width, int height)
|
|
||||||
{
|
|
||||||
glUniform2i(m_uniforms.viewport_size, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_color(float r, float g, float b, float a)
|
|
||||||
{
|
|
||||||
glUniform4f(m_uniforms.color, r, g, b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_position(int x, int y)
|
|
||||||
{
|
|
||||||
glUniform2i(m_uniforms.position, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::shared_ptr<glcxx::Program> m_program;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
GLint viewport_size;
|
|
||||||
GLint color;
|
|
||||||
GLint position;
|
|
||||||
} m_uniforms;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,51 +0,0 @@
|
|||||||
#include "GL.h"
|
|
||||||
|
|
||||||
GL::GL()
|
|
||||||
{
|
|
||||||
m_shaders.text = std::make_shared<TextShader>();
|
|
||||||
m_shaders.text->use();
|
|
||||||
m_shaders.text->set_texture(0);
|
|
||||||
m_shaders.text->set_color(1.0, 1.0, 1.0, 1.0);
|
|
||||||
|
|
||||||
m_shaders.rect = std::make_shared<RectShader>();
|
|
||||||
|
|
||||||
GLint rect_coords[] = {
|
|
||||||
0, 0,
|
|
||||||
1, 0,
|
|
||||||
1, 1,
|
|
||||||
0, 1};
|
|
||||||
m_rect_array = glcxx::Array::create();
|
|
||||||
m_rect_array->bind();
|
|
||||||
m_rect_buffer = glcxx::Buffer::create(GL_ARRAY_BUFFER, GL_STATIC_DRAW,
|
|
||||||
rect_coords, sizeof(rect_coords));
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GL::draw_rect(int x, int y, int width, int height,
|
|
||||||
float r, float g, float b, float a)
|
|
||||||
{
|
|
||||||
m_rect_array->bind();
|
|
||||||
m_shaders.rect->use();
|
|
||||||
m_shaders.rect->set_color(r, g, b, a);
|
|
||||||
m_shaders.rect->set_position(x, y);
|
|
||||||
m_shaders.rect->set_size(width, height);
|
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GL::draw_character(int x, int y, uint32_t character, Font & font,
|
|
||||||
float r, float g, float b, float a)
|
|
||||||
{
|
|
||||||
m_shaders.text->use();
|
|
||||||
m_shaders.text->set_color(r, g, b, a);
|
|
||||||
m_shaders.text->set_position(x, y + font.get_baseline_offset());
|
|
||||||
font.get_glyph(character)->render();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GL::resize(int width, int height)
|
|
||||||
{
|
|
||||||
m_shaders.text->use();
|
|
||||||
m_shaders.text->set_viewport_size(width, height);
|
|
||||||
m_shaders.rect->use();
|
|
||||||
m_shaders.rect->set_viewport_size(width, height);
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
#ifndef GL_H
|
|
||||||
#define GL_H
|
|
||||||
|
|
||||||
#include "glcxx.hpp"
|
|
||||||
#include "TextShader.h"
|
|
||||||
#include "FlatShader.h"
|
|
||||||
#include "RectShader.h"
|
|
||||||
#include "Font.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class GL
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GL();
|
|
||||||
|
|
||||||
void draw_rect(int x, int y, int width, int height,
|
|
||||||
float r, float g, float b, float a);
|
|
||||||
void draw_character(int x, int y, uint32_t character, Font & font,
|
|
||||||
float r, float g, float b, float a);
|
|
||||||
void resize(int width, int height);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
std::shared_ptr<TextShader> text;
|
|
||||||
std::shared_ptr<FlatShader> flat;
|
|
||||||
std::shared_ptr<RectShader> rect;
|
|
||||||
} m_shaders;
|
|
||||||
|
|
||||||
std::shared_ptr<glcxx::Array> m_rect_array;
|
|
||||||
std::shared_ptr<glcxx::Buffer> m_rect_buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||||||
#include "RectShader.h"
|
|
||||||
#include "Runtime.h"
|
|
||||||
|
|
||||||
RectShader::RectShader()
|
|
||||||
{
|
|
||||||
std::string v_path = Runtime::find(Runtime::SHADER, "rect.v");
|
|
||||||
std::string f_path = Runtime::find(Runtime::SHADER, "rect.f");
|
|
||||||
|
|
||||||
m_program = glcxx::Program::create(
|
|
||||||
glcxx::Shader::create_from_file(GL_VERTEX_SHADER, v_path.c_str()),
|
|
||||||
glcxx::Shader::create_from_file(GL_FRAGMENT_SHADER, f_path.c_str()),
|
|
||||||
"coords", 0);
|
|
||||||
|
|
||||||
m_uniforms.viewport_size = m_program->get_uniform_location("viewport_size");
|
|
||||||
m_uniforms.color = m_program->get_uniform_location("color");
|
|
||||||
m_uniforms.position = m_program->get_uniform_location("position");
|
|
||||||
m_uniforms.size = m_program->get_uniform_location("size");
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
#ifndef RECTSHADER_H
|
|
||||||
#define RECTSHADER_H
|
|
||||||
|
|
||||||
#include "glcxx.hpp"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class RectShader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RectShader();
|
|
||||||
|
|
||||||
void use() { m_program->use(); }
|
|
||||||
|
|
||||||
void set_viewport_size(int width, int height)
|
|
||||||
{
|
|
||||||
glUniform2i(m_uniforms.viewport_size, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_color(float r, float g, float b, float a)
|
|
||||||
{
|
|
||||||
glUniform4f(m_uniforms.color, r, g, b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_position(int x, int y)
|
|
||||||
{
|
|
||||||
glUniform2i(m_uniforms.position, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_size(int x, int y)
|
|
||||||
{
|
|
||||||
glUniform2i(m_uniforms.size, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::shared_ptr<glcxx::Program> m_program;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
GLint viewport_size;
|
|
||||||
GLint color;
|
|
||||||
GLint position;
|
|
||||||
GLint size;
|
|
||||||
} m_uniforms;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||||||
#include "TextShader.h"
|
|
||||||
#include "Runtime.h"
|
|
||||||
|
|
||||||
TextShader::TextShader()
|
|
||||||
{
|
|
||||||
std::string v_path = Runtime::find(Runtime::SHADER, "text.v");
|
|
||||||
std::string f_path = Runtime::find(Runtime::SHADER, "text.f");
|
|
||||||
|
|
||||||
m_program = glcxx::Program::create(
|
|
||||||
glcxx::Shader::create_from_file(GL_VERTEX_SHADER, v_path.c_str()),
|
|
||||||
glcxx::Shader::create_from_file(GL_FRAGMENT_SHADER, f_path.c_str()),
|
|
||||||
"coords", 0);
|
|
||||||
|
|
||||||
m_uniforms.viewport_size = m_program->get_uniform_location("viewport_size");
|
|
||||||
m_uniforms.texture = m_program->get_uniform_location("texture");
|
|
||||||
m_uniforms.color = m_program->get_uniform_location("color");
|
|
||||||
m_uniforms.position = m_program->get_uniform_location("position");
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
#ifndef TEXTSHADER_H
|
|
||||||
#define TEXTSHADER_H
|
|
||||||
|
|
||||||
#include "glcxx.hpp"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class TextShader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TextShader();
|
|
||||||
|
|
||||||
void use() { m_program->use(); }
|
|
||||||
|
|
||||||
void set_viewport_size(int width, int height)
|
|
||||||
{
|
|
||||||
glUniform2i(m_uniforms.viewport_size, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_texture(int texture)
|
|
||||||
{
|
|
||||||
glUniform1i(m_uniforms.texture, texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_color(float r, float g, float b, float a)
|
|
||||||
{
|
|
||||||
glUniform4f(m_uniforms.color, r, g, b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_position(int x, int y)
|
|
||||||
{
|
|
||||||
glUniform2i(m_uniforms.position, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::shared_ptr<glcxx::Program> m_program;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
GLint viewport_size;
|
|
||||||
GLint texture;
|
|
||||||
GLint color;
|
|
||||||
GLint position;
|
|
||||||
} m_uniforms;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,59 +0,0 @@
|
|||||||
#include "Jtk.h"
|
|
||||||
|
|
||||||
#ifdef JTK_X
|
|
||||||
|
|
||||||
#include <GL/glx.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
Display * g_display;
|
|
||||||
XVisualInfo * g_vi;
|
|
||||||
XSetWindowAttributes g_swa;
|
|
||||||
GLXContext g_context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the Jtk subsystem.
|
|
||||||
*
|
|
||||||
* @return true on success, false on failure
|
|
||||||
*/
|
|
||||||
bool Jtk_Init()
|
|
||||||
{
|
|
||||||
static int glx_attribute_list[] = {
|
|
||||||
GLX_RGBA,
|
|
||||||
GLX_DOUBLEBUFFER,
|
|
||||||
None,
|
|
||||||
};
|
|
||||||
|
|
||||||
g_display = XOpenDisplay(NULL);
|
|
||||||
if (g_display == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "XOpenDisplay() failure\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_vi = glXChooseVisual(g_display, DefaultScreen(g_display),
|
|
||||||
glx_attribute_list);
|
|
||||||
if (g_vi == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "glXChooseVisual() failure\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_context = glXCreateContext(g_display, g_vi, NULL, True);
|
|
||||||
if (g_context == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "glXCreateContext() failure\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Colormap colormap = XCreateColormap(g_display,
|
|
||||||
RootWindow(g_display, g_vi->screen), g_vi->visual, AllocNone);
|
|
||||||
g_swa.colormap = colormap;
|
|
||||||
g_swa.border_pixel = 0;
|
|
||||||
g_swa.event_mask = StructureNotifyMask |
|
|
||||||
KeyPressMask | KeyReleaseMask |
|
|
||||||
ButtonPressMask | ButtonReleaseMask;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,12 +0,0 @@
|
|||||||
#ifndef JTK_H
|
|
||||||
#define JTK_H
|
|
||||||
|
|
||||||
#include "Jtk_event.h"
|
|
||||||
#include "keys.h"
|
|
||||||
#include "Jtk_time.h"
|
|
||||||
#include "Jtk_timer.h"
|
|
||||||
#include "Jtk_window.h"
|
|
||||||
|
|
||||||
bool Jtk_Init();
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,482 +0,0 @@
|
|||||||
#include "Jtk.h"
|
|
||||||
|
|
||||||
#ifdef JTK_X
|
|
||||||
|
|
||||||
#include <GL/glx.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "Jtk_internal.h"
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
/** Do not wait longer than 100ms */
|
|
||||||
#define MAX_WAIT_TIME 100000u
|
|
||||||
|
|
||||||
static std::unordered_map<unsigned int, size_t> g_repeating_keys;
|
|
||||||
static std::unordered_map<size_t, unsigned int> g_key_repeat_timers;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void StopKeyRepeat(unsigned int x_keycode)
|
|
||||||
{
|
|
||||||
auto it = g_repeating_keys.find(x_keycode);
|
|
||||||
if (it != g_repeating_keys.end())
|
|
||||||
{
|
|
||||||
size_t timer_id = it->second;
|
|
||||||
Jtk_RemoveTimer(timer_id);
|
|
||||||
g_repeating_keys.erase(x_keycode);
|
|
||||||
g_key_repeat_timers.erase(timer_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static unsigned int GetXState()
|
|
||||||
{
|
|
||||||
Window win;
|
|
||||||
int i;
|
|
||||||
unsigned int state;
|
|
||||||
XQueryPointer(g_display, RootWindow(g_display, DefaultScreen(g_display)), &win, &win, &i, &i, &i, &i, &state);
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static uint32_t XStateToJtkKeyMods(unsigned int x_state)
|
|
||||||
{
|
|
||||||
uint32_t mods = 0u;
|
|
||||||
/* OR in the modifier states */
|
|
||||||
if (x_state & ShiftMask)
|
|
||||||
{
|
|
||||||
mods |= JES_KEY_MODS_SHIFT;
|
|
||||||
}
|
|
||||||
if (x_state & LockMask)
|
|
||||||
{
|
|
||||||
mods |= JES_KEY_MODS_LOCK;
|
|
||||||
}
|
|
||||||
if (x_state & ControlMask)
|
|
||||||
{
|
|
||||||
mods |= JES_KEY_MODS_CTRL;
|
|
||||||
}
|
|
||||||
return mods;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t XKeyToJtkKey(unsigned int x_keycode, unsigned int x_state)
|
|
||||||
{
|
|
||||||
XKeyEvent x_key_event;
|
|
||||||
x_key_event.type = KeyPress;
|
|
||||||
x_key_event.display = g_display;
|
|
||||||
/* Turn off the ControlMask bit for looking up keys. We'll handle control
|
|
||||||
* keys ourselves. */
|
|
||||||
x_key_event.state = x_state & ~ControlMask;
|
|
||||||
x_key_event.keycode = x_keycode;
|
|
||||||
char buffer;
|
|
||||||
KeySym keysym;
|
|
||||||
uint32_t key = JES_KEY_UNKNOWN;
|
|
||||||
|
|
||||||
if (XLookupString(&x_key_event, &buffer, 1, &keysym, nullptr) > 0)
|
|
||||||
{
|
|
||||||
if (buffer == '\r')
|
|
||||||
{
|
|
||||||
key = '\n';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
key = buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (keysym)
|
|
||||||
{
|
|
||||||
case XK_F1: key = JES_KEY_F1; break;
|
|
||||||
case XK_F2: key = JES_KEY_F2; break;
|
|
||||||
case XK_F3: key = JES_KEY_F3; break;
|
|
||||||
case XK_F4: key = JES_KEY_F4; break;
|
|
||||||
case XK_F5: key = JES_KEY_F5; break;
|
|
||||||
case XK_F6: key = JES_KEY_F6; break;
|
|
||||||
case XK_F7: key = JES_KEY_F7; break;
|
|
||||||
case XK_F8: key = JES_KEY_F8; break;
|
|
||||||
case XK_F9: key = JES_KEY_F9; break;
|
|
||||||
case XK_F10: key = JES_KEY_F10; break;
|
|
||||||
case XK_F11: key = JES_KEY_F11; break;
|
|
||||||
case XK_F12: key = JES_KEY_F12; break;
|
|
||||||
case XK_F13: key = JES_KEY_F13; break;
|
|
||||||
case XK_F14: key = JES_KEY_F14; break;
|
|
||||||
case XK_F15: key = JES_KEY_F15; break;
|
|
||||||
case XK_F16: key = JES_KEY_F16; break;
|
|
||||||
case XK_F17: key = JES_KEY_F17; break;
|
|
||||||
case XK_F18: key = JES_KEY_F18; break;
|
|
||||||
case XK_F19: key = JES_KEY_F19; break;
|
|
||||||
case XK_F20: key = JES_KEY_F20; break;
|
|
||||||
case XK_F21: key = JES_KEY_F21; break;
|
|
||||||
case XK_F22: key = JES_KEY_F22; break;
|
|
||||||
case XK_F23: key = JES_KEY_F23; break;
|
|
||||||
case XK_F24: key = JES_KEY_F24; break;
|
|
||||||
case XK_F25: key = JES_KEY_F25; break;
|
|
||||||
case XK_F26: key = JES_KEY_F26; break;
|
|
||||||
case XK_F27: key = JES_KEY_F27; break;
|
|
||||||
case XK_F28: key = JES_KEY_F28; break;
|
|
||||||
case XK_F29: key = JES_KEY_F29; break;
|
|
||||||
case XK_F30: key = JES_KEY_F30; break;
|
|
||||||
case XK_F31: key = JES_KEY_F31; break;
|
|
||||||
|
|
||||||
case XK_Shift_L: key = JES_KEY_SHIFT_L; break;
|
|
||||||
case XK_Shift_R: key = JES_KEY_SHIFT_R; break;
|
|
||||||
case XK_Control_L: key = JES_KEY_CTRL_L; break;
|
|
||||||
case XK_Control_R: key = JES_KEY_CTRL_R; break;
|
|
||||||
case XK_Caps_Lock: key = JES_KEY_CAPS_LOCK; break;
|
|
||||||
case XK_Shift_Lock: key = JES_KEY_SHIFT_LOCK;break;
|
|
||||||
|
|
||||||
case XK_Meta_L: key = JES_KEY_META_L; break;
|
|
||||||
case XK_Meta_R: key = JES_KEY_META_R; break;
|
|
||||||
case XK_Alt_L: key = JES_KEY_ALT_L; break;
|
|
||||||
case XK_Alt_R: key = JES_KEY_ALT_R; break;
|
|
||||||
case XK_Super_L: key = JES_KEY_SUPER_L; break;
|
|
||||||
case XK_Super_R: key = JES_KEY_SUPER_R; break;
|
|
||||||
|
|
||||||
case XK_Home: key = JES_KEY_HOME; break;
|
|
||||||
case XK_Left: key = JES_KEY_LEFT; break;
|
|
||||||
case XK_Up: key = JES_KEY_UP; break;
|
|
||||||
case XK_Right: key = JES_KEY_RIGHT; break;
|
|
||||||
case XK_Down: key = JES_KEY_DOWN; break;
|
|
||||||
case XK_Page_Up: key = JES_KEY_PAGE_UP; break;
|
|
||||||
case XK_Page_Down: key = JES_KEY_PAGE_DOWN; break;
|
|
||||||
case XK_End: key = JES_KEY_END; break;
|
|
||||||
case XK_Begin: key = JES_KEY_BEGIN; break;
|
|
||||||
|
|
||||||
case XK_Select: key = JES_KEY_SELECT; break;
|
|
||||||
case XK_Print: key = JES_KEY_PRINT; break;
|
|
||||||
case XK_Execute: key = JES_KEY_EXECUTE; break;
|
|
||||||
case XK_Insert: key = JES_KEY_INSERT; break;
|
|
||||||
case XK_Undo: key = JES_KEY_UNDO; break;
|
|
||||||
case XK_Redo: key = JES_KEY_REDO; break;
|
|
||||||
case XK_Menu: key = JES_KEY_MENU; break;
|
|
||||||
case XK_Find: key = JES_KEY_FIND; break;
|
|
||||||
case XK_Cancel: key = JES_KEY_CANCEL; break;
|
|
||||||
case XK_Help: key = JES_KEY_HELP; break;
|
|
||||||
case XK_Break: key = JES_KEY_BREAK; break;
|
|
||||||
case XK_Num_Lock: key = JES_KEY_NUM_LOCK; break;
|
|
||||||
|
|
||||||
case XK_KP_Space: key = JES_KEY_KP_SPACE; break;
|
|
||||||
case XK_KP_Tab: key = JES_KEY_KP_TAB; break;
|
|
||||||
case XK_KP_Enter: key = JES_KEY_KP_ENTER; break;
|
|
||||||
case XK_KP_F1: key = JES_KEY_KP_F1; break;
|
|
||||||
case XK_KP_F2: key = JES_KEY_KP_F2; break;
|
|
||||||
case XK_KP_F3: key = JES_KEY_KP_F3; break;
|
|
||||||
case XK_KP_F4: key = JES_KEY_KP_F4; break;
|
|
||||||
case XK_KP_Home: key = JES_KEY_KP_HOME; break;
|
|
||||||
case XK_KP_Left: key = JES_KEY_KP_LEFT; break;
|
|
||||||
case XK_KP_Up: key = JES_KEY_KP_UP; break;
|
|
||||||
case XK_KP_Right: key = JES_KEY_KP_RIGHT; break;
|
|
||||||
case XK_KP_Down: key = JES_KEY_KP_DOWN; break;
|
|
||||||
case XK_KP_Page_Up: key = JES_KEY_KP_PAGE_UP; break;
|
|
||||||
case XK_KP_Page_Down: key = JES_KEY_KP_PAGE_DOWN; break;
|
|
||||||
case XK_KP_End: key = JES_KEY_KP_END; break;
|
|
||||||
case XK_KP_Begin: key = JES_KEY_KP_BEGIN; break;
|
|
||||||
case XK_KP_Insert: key = JES_KEY_KP_INSERT; break;
|
|
||||||
case XK_KP_Delete: key = JES_KEY_KP_DELETE; break;
|
|
||||||
case XK_KP_Equal: key = JES_KEY_KP_EQUAL; break;
|
|
||||||
case XK_KP_Multiply: key = JES_KEY_KP_MULTIPLY; break;
|
|
||||||
case XK_KP_Add: key = JES_KEY_KP_ADD; break;
|
|
||||||
case XK_KP_Separator: key = JES_KEY_KP_SEPARATOR; break;
|
|
||||||
case XK_KP_Subtract: key = JES_KEY_KP_SUBTRACT; break;
|
|
||||||
case XK_KP_Decimal: key = JES_KEY_KP_DECIMAL; break;
|
|
||||||
case XK_KP_Divide: key = JES_KEY_KP_DIVIDE; break;
|
|
||||||
|
|
||||||
case XK_KP_0: key = JES_KEY_KP_0; break;
|
|
||||||
case XK_KP_1: key = JES_KEY_KP_1; break;
|
|
||||||
case XK_KP_2: key = JES_KEY_KP_2; break;
|
|
||||||
case XK_KP_3: key = JES_KEY_KP_3; break;
|
|
||||||
case XK_KP_4: key = JES_KEY_KP_4; break;
|
|
||||||
case XK_KP_5: key = JES_KEY_KP_5; break;
|
|
||||||
case XK_KP_6: key = JES_KEY_KP_6; break;
|
|
||||||
case XK_KP_7: key = JES_KEY_KP_7; break;
|
|
||||||
case XK_KP_8: key = JES_KEY_KP_8; break;
|
|
||||||
case XK_KP_9: key = JES_KEY_KP_9; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* OR in the modifier states */
|
|
||||||
key |= XStateToJtkKeyMods(x_state);
|
|
||||||
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static Bool KeyRepeatCheckIfEvent(Display * display, XEvent * chkev,
|
|
||||||
XPointer arg)
|
|
||||||
{
|
|
||||||
XEvent * release_event = (XEvent *)arg;
|
|
||||||
if (chkev->type == KeyPress &&
|
|
||||||
chkev->xkey.keycode == release_event->xkey.keycode &&
|
|
||||||
chkev->xkey.time - release_event->xkey.time < 2)
|
|
||||||
return True;
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if this is a repeated key.
|
|
||||||
*/
|
|
||||||
static bool IsRepeatKey(Display * display, XEvent * event)
|
|
||||||
{
|
|
||||||
XEvent dummyev;
|
|
||||||
if (XPending(display))
|
|
||||||
{
|
|
||||||
if (XCheckIfEvent(display, &dummyev, KeyRepeatCheckIfEvent,
|
|
||||||
(XPointer)event) == True)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static Bool MatchKeyPress(Display * display, XEvent * event, XPointer arg)
|
|
||||||
{
|
|
||||||
XEvent * match_event = (XEvent *)arg;
|
|
||||||
return (event->type == match_event->type) &&
|
|
||||||
(event->xkey.window == match_event->xkey.window) &&
|
|
||||||
(event->xkey.state == match_event->xkey.state) &&
|
|
||||||
(event->xkey.keycode == match_event->xkey.keycode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process an X key press event.
|
|
||||||
*
|
|
||||||
* @param x_event
|
|
||||||
* Pointer to the X event.
|
|
||||||
* @param event
|
|
||||||
* Pointer to the Jtk event.
|
|
||||||
*/
|
|
||||||
static bool ProcessXKeyPressEvent(XEvent * x_event, Jtk_Event * event)
|
|
||||||
{
|
|
||||||
unsigned int x_keycode = x_event->xkey.keycode;
|
|
||||||
event->type = JTK_EVENT_KEY_PRESS;
|
|
||||||
event->key.repeat = false;
|
|
||||||
event->key.key = XKeyToJtkKey(x_keycode, x_event->xkey.state);
|
|
||||||
event->key.x_keycode = x_keycode;
|
|
||||||
/* Remove any following keypress events for the same keycode from the X
|
|
||||||
* queue. */
|
|
||||||
XEvent remove_event;
|
|
||||||
while (XCheckIfEvent(g_display, &remove_event, MatchKeyPress, (XPointer)x_event) == True)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process an X key release event.
|
|
||||||
*
|
|
||||||
* @param x_event
|
|
||||||
* Pointer to the X event.
|
|
||||||
* @param event
|
|
||||||
* Pointer to the Jtk event.
|
|
||||||
*/
|
|
||||||
static bool ProcessXKeyReleaseEvent(XEvent * x_event, Jtk_Event * event)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
if (IsRepeatKey(g_display, x_event))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
StopKeyRepeat(x_event->xkey.keycode);
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Bool MatchButtonPress(Display * display, XEvent * event, XPointer arg)
|
|
||||||
{
|
|
||||||
XEvent * match_event = (XEvent *)arg;
|
|
||||||
return (event->type == match_event->type) &&
|
|
||||||
(event->xbutton.window == match_event->xbutton.window) &&
|
|
||||||
(event->xbutton.state == match_event->xbutton.state) &&
|
|
||||||
(event->xbutton.button == match_event->xbutton.button);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process an X button press event.
|
|
||||||
*/
|
|
||||||
static bool ProcessXButtonPressEvent(XEvent * x_event, Jtk_Event * event)
|
|
||||||
{
|
|
||||||
event->type = JTK_EVENT_BUTTON_PRESS;
|
|
||||||
event->button.mods = XStateToJtkKeyMods(x_event->xbutton.state);
|
|
||||||
event->button.button = x_event->xbutton.button;
|
|
||||||
/* If this is a mouse wheel scroll event, remove any following scroll
|
|
||||||
* events. */
|
|
||||||
if ((event->button.button == 4) || (event->button.button == 5))
|
|
||||||
{
|
|
||||||
XEvent remove_event;
|
|
||||||
while (XCheckIfEvent(g_display, &remove_event, MatchButtonPress, (XPointer)x_event) == True)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process an X configure event.
|
|
||||||
*
|
|
||||||
* @param x_event
|
|
||||||
* Pointer to the X event.
|
|
||||||
* @param event
|
|
||||||
* Pointer to the Jtk event.
|
|
||||||
*/
|
|
||||||
static bool ProcessConfigureEvent(XEvent * x_event, Jtk_Event * event)
|
|
||||||
{
|
|
||||||
event->type = JTK_EVENT_WINDOW_RESIZE;
|
|
||||||
event->resize.width = x_event->xconfigure.width;
|
|
||||||
event->resize.height = x_event->xconfigure.height;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process an X ClientMessage event.
|
|
||||||
*
|
|
||||||
* @param x_event
|
|
||||||
* Pointer to the X event.
|
|
||||||
* @param event
|
|
||||||
* Pointer to the Jtk event.
|
|
||||||
*/
|
|
||||||
static bool ProcessXClientMessageEvent(XEvent * x_event, Jtk_Event * event)
|
|
||||||
{
|
|
||||||
Atom wm_delete_window_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", False);
|
|
||||||
if (x_event->xclient.data.l[0] == (long)wm_delete_window_atom)
|
|
||||||
{
|
|
||||||
event->type = JTK_EVENT_WINDOW_CLOSE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process an X event.
|
|
||||||
*
|
|
||||||
* @param x_event
|
|
||||||
* Pointer to the X event.
|
|
||||||
* @param event
|
|
||||||
* Pointer to the Jtk event.
|
|
||||||
*
|
|
||||||
* @retval true
|
|
||||||
* The event should be passed to the user and event has been filled in.
|
|
||||||
* @retval false
|
|
||||||
* The event should not be passed to the user.
|
|
||||||
*/
|
|
||||||
static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event)
|
|
||||||
{
|
|
||||||
switch (x_event->type)
|
|
||||||
{
|
|
||||||
case KeyPress:
|
|
||||||
return ProcessXKeyPressEvent(x_event, event);
|
|
||||||
|
|
||||||
case KeyRelease:
|
|
||||||
return ProcessXKeyReleaseEvent(x_event, event);
|
|
||||||
|
|
||||||
case ButtonPress:
|
|
||||||
return ProcessXButtonPressEvent(x_event, event);
|
|
||||||
|
|
||||||
case ButtonRelease:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Expose:
|
|
||||||
event->type = JTK_EVENT_WINDOW_EXPOSE;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GraphicsExpose:
|
|
||||||
event->type = JTK_EVENT_WINDOW_EXPOSE;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MapNotify:
|
|
||||||
event->type = JTK_EVENT_WINDOW_EXPOSE;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case ConfigureNotify:
|
|
||||||
return ProcessConfigureEvent(x_event, event);
|
|
||||||
|
|
||||||
case ClientMessage:
|
|
||||||
return ProcessXClientMessageEvent(x_event, event);
|
|
||||||
|
|
||||||
case MappingNotify:
|
|
||||||
XRefreshKeyboardMapping(&x_event->xmapping);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Jtk_CheckEvent(Jtk_Event * event)
|
|
||||||
{
|
|
||||||
/* First check for an X event. */
|
|
||||||
while (XPending(g_display) > 0)
|
|
||||||
{
|
|
||||||
XEvent x_event;
|
|
||||||
XNextEvent(g_display, &x_event);
|
|
||||||
if (ProcessXEvent(&x_event, event))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Next check if any timer has expired. */
|
|
||||||
size_t timer_id = Jtk_GetExpiredTimer();
|
|
||||||
if (timer_id != (size_t)-1)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
auto it = g_key_repeat_timers.find(timer_id);
|
|
||||||
if (it != g_key_repeat_timers.end())
|
|
||||||
{
|
|
||||||
event->type = JTK_EVENT_KEY_PRESS;
|
|
||||||
event->key.repeat = true;
|
|
||||||
event->key.key = XKeyToJtkKey(it->second);
|
|
||||||
event->key.x_keycode = it->second;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
event->type = JTK_EVENT_TIMER;
|
|
||||||
event->timer.timer_id = timer_id;
|
|
||||||
event->timer.user1 = Jtk_GetTimerUserData(timer_id, 0u);
|
|
||||||
event->timer.user2 = Jtk_GetTimerUserData(timer_id, 1u);
|
|
||||||
#if 0
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
Jtk_ServiceTimer(timer_id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jtk_WaitEvent(Jtk_Event * event)
|
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (Jtk_CheckEvent(event))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Wait for something to happen. */
|
|
||||||
uint64_t time_to_wait = Jtk_TimeToNextTimerExpiration();
|
|
||||||
if (time_to_wait > MAX_WAIT_TIME)
|
|
||||||
{
|
|
||||||
time_to_wait = MAX_WAIT_TIME;
|
|
||||||
}
|
|
||||||
|
|
||||||
int x_fd = ConnectionNumber(g_display);
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(x_fd, &fds);
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = time_to_wait / 1000000u;
|
|
||||||
tv.tv_usec = time_to_wait % 1000000u;
|
|
||||||
select(x_fd + 1, &fds, nullptr, nullptr, &tv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t interval)
|
|
||||||
{
|
|
||||||
StopKeyRepeat(key_event->x_keycode);
|
|
||||||
size_t timer_id = Jtk_AddTimer(delay, interval, nullptr, nullptr);
|
|
||||||
g_repeating_keys[key_event->x_keycode] = timer_id;
|
|
||||||
g_key_repeat_timers[timer_id] = key_event->x_keycode;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,62 +0,0 @@
|
|||||||
#ifndef JTK_EVENT_H
|
|
||||||
#define JTK_EVENT_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define JTK_EVENT_WINDOW_CLOSE 1u
|
|
||||||
#define JTK_EVENT_WINDOW_EXPOSE 2u
|
|
||||||
#define JTK_EVENT_KEY_PRESS 3u
|
|
||||||
#define JTK_EVENT_KEY_RELEASE 4u
|
|
||||||
#define JTK_EVENT_BUTTON_PRESS 5u
|
|
||||||
#define JTK_EVENT_BUTTON_RELEASE 6u
|
|
||||||
#define JTK_EVENT_TIMER 7u
|
|
||||||
#define JTK_EVENT_WINDOW_RESIZE 8u
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
bool repeat;
|
|
||||||
uint32_t key;
|
|
||||||
#ifdef JTK_X
|
|
||||||
unsigned int x_keycode;
|
|
||||||
#endif
|
|
||||||
} Jtk_KeyEvent;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t mods;
|
|
||||||
uint8_t button;
|
|
||||||
} Jtk_ButtonEvent;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
size_t timer_id;
|
|
||||||
void * user1;
|
|
||||||
void * user2;
|
|
||||||
} Jtk_TimerEvent;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
size_t width;
|
|
||||||
size_t height;
|
|
||||||
} Jtk_WindowResizeEvent;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t type;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
Jtk_KeyEvent key;
|
|
||||||
Jtk_ButtonEvent button;
|
|
||||||
Jtk_TimerEvent timer;
|
|
||||||
Jtk_WindowResizeEvent resize;
|
|
||||||
};
|
|
||||||
} Jtk_Event;
|
|
||||||
|
|
||||||
bool Jtk_CheckEvent(Jtk_Event * event);
|
|
||||||
void Jtk_WaitEvent(Jtk_Event * event);
|
|
||||||
#if 0
|
|
||||||
void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t interval);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,9 +0,0 @@
|
|||||||
#ifndef JTK_INTERNAL_H
|
|
||||||
#define JTK_INTERNAL_H
|
|
||||||
|
|
||||||
extern Display * g_display;
|
|
||||||
extern XVisualInfo * g_vi;
|
|
||||||
extern XSetWindowAttributes g_swa;
|
|
||||||
extern GLXContext g_context;
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,9 +0,0 @@
|
|||||||
#include "Jtk.h"
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
uint64_t Jtk_UsTime()
|
|
||||||
{
|
|
||||||
struct timeval tv;
|
|
||||||
gettimeofday(&tv, nullptr);
|
|
||||||
return (uint64_t)tv.tv_sec * 1000000u + (uint64_t)tv.tv_usec;
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
#ifndef JTK_TIME_H
|
|
||||||
#define JTK_TIME_H
|
|
||||||
|
|
||||||
#include "Jtk_timer.h"
|
|
||||||
|
|
||||||
bool Jtk_Init();
|
|
||||||
uint64_t Jtk_UsTime();
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,157 +0,0 @@
|
|||||||
#include "Jtk.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint64_t next; /**< Time the timer next expires (us). */
|
|
||||||
uint64_t interval; /**< Timer interval (us). */
|
|
||||||
size_t id; /**< Timer ID. */
|
|
||||||
void * user[2]; /**< User data pointers. */
|
|
||||||
} Timer;
|
|
||||||
|
|
||||||
/** Vector used to allocate timer IDs. */
|
|
||||||
static std::vector<std::shared_ptr<Timer>> g_timers;
|
|
||||||
|
|
||||||
/** Linked list used to traverse all active timers. */
|
|
||||||
static std::list<std::shared_ptr<Timer>> g_active_timers;
|
|
||||||
|
|
||||||
static size_t AllocateTimerID()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < g_timers.size(); i++)
|
|
||||||
{
|
|
||||||
if (!g_timers[i])
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_timers.push_back(nullptr);
|
|
||||||
return g_timers.size() - 1u;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a timer.
|
|
||||||
*
|
|
||||||
* @param delay
|
|
||||||
* Delay time in milliseconds.
|
|
||||||
* @param interval
|
|
||||||
* Interval time in milliseconds. A value of 0 indicates that the timer
|
|
||||||
* is not periodic.
|
|
||||||
* @param user1
|
|
||||||
* User data pointer 1. This value is not used by Jtk but can be retrieved by
|
|
||||||
* the user when a timer expires.
|
|
||||||
* @param user2
|
|
||||||
* User data pointer 2. This value is not used by Jtk but can be retrieved by
|
|
||||||
* the user when a timer expires.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Timer ID.
|
|
||||||
*/
|
|
||||||
size_t Jtk_AddTimer(uint32_t delay, uint32_t interval, void * user1, void * user2)
|
|
||||||
{
|
|
||||||
uint64_t current_system_time = Jtk_UsTime();
|
|
||||||
size_t timer_id = AllocateTimerID();
|
|
||||||
auto timer = std::make_shared<Timer>();
|
|
||||||
timer->next = current_system_time + (delay * 1000u);
|
|
||||||
timer->interval = interval * 1000u;
|
|
||||||
timer->id = timer_id;
|
|
||||||
timer->user[0] = user1;
|
|
||||||
timer->user[1] = user2;
|
|
||||||
g_timers[timer_id] = timer;
|
|
||||||
g_active_timers.push_back(timer);
|
|
||||||
return timer_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a timer.
|
|
||||||
*
|
|
||||||
* @param timer_id
|
|
||||||
* The ID of the timer to remove.
|
|
||||||
*/
|
|
||||||
void Jtk_RemoveTimer(size_t timer_id)
|
|
||||||
{
|
|
||||||
if (timer_id < g_timers.size())
|
|
||||||
{
|
|
||||||
auto timer = g_timers[timer_id];
|
|
||||||
g_active_timers.remove(timer);
|
|
||||||
g_timers[timer_id] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the amount of time until the next timer expires (in us).
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Time (in us) until the next timer expires. This will be 0 if an active
|
|
||||||
* timer has already expired, and will be (uint64_t)-1 if there are no
|
|
||||||
* active timers.
|
|
||||||
*/
|
|
||||||
uint64_t Jtk_TimeToNextTimerExpiration()
|
|
||||||
{
|
|
||||||
uint64_t time = (uint64_t)-1;
|
|
||||||
uint64_t current_system_time = Jtk_UsTime();
|
|
||||||
for (auto & timer : g_active_timers)
|
|
||||||
{
|
|
||||||
if (timer->next <= current_system_time)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint64_t time_until_this_timer = timer->next - current_system_time;
|
|
||||||
if (time_until_this_timer < time)
|
|
||||||
{
|
|
||||||
time = time_until_this_timer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service a timer.
|
|
||||||
*
|
|
||||||
* This will increment the timer's next activation time by its interval, or
|
|
||||||
* for a timer with an interval of 0, will remove the timer.
|
|
||||||
*
|
|
||||||
* @param timer_id
|
|
||||||
* The ID of the timer to service.
|
|
||||||
*/
|
|
||||||
void Jtk_ServiceTimer(size_t timer_id)
|
|
||||||
{
|
|
||||||
auto timer = g_timers[timer_id];
|
|
||||||
if (timer->interval == 0u)
|
|
||||||
{
|
|
||||||
Jtk_RemoveTimer(timer_id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
timer->next += timer->interval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the ID of an expired timer.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The ID of an expired timer, or (size_t)-1 if no timer is expired.
|
|
||||||
*/
|
|
||||||
size_t Jtk_GetExpiredTimer()
|
|
||||||
{
|
|
||||||
uint64_t current_system_time = Jtk_UsTime();
|
|
||||||
for (auto & timer : g_active_timers)
|
|
||||||
{
|
|
||||||
if (timer->next <= current_system_time)
|
|
||||||
{
|
|
||||||
return timer->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (size_t)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void * Jtk_GetTimerUserData(size_t timer_id, uint8_t index)
|
|
||||||
{
|
|
||||||
if (timer_id < g_timers.size())
|
|
||||||
{
|
|
||||||
return g_timers[timer_id]->user[index];
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
#ifndef JTK_TIMER_H
|
|
||||||
#define JTK_TIMER_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
size_t Jtk_AddTimer(uint32_t delay, uint32_t interval, void * user1, void * user2);
|
|
||||||
void Jtk_RemoveTimer(size_t timer_id);
|
|
||||||
uint64_t Jtk_TimeToNextTimerExpiration();
|
|
||||||
void Jtk_ServiceTimer(size_t timer_id);
|
|
||||||
size_t Jtk_GetExpiredTimer();
|
|
||||||
void * Jtk_GetTimerUserData(size_t timer_id, uint8_t index);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,95 +0,0 @@
|
|||||||
#include "Jtk.h"
|
|
||||||
|
|
||||||
#ifdef JTK_X
|
|
||||||
|
|
||||||
#include <GL/glx.h>
|
|
||||||
#include "Jtk_internal.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <X11/Xatom.h>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
static Bool WaitForNotify(Display * display, XEvent * event, XPointer arg)
|
|
||||||
{
|
|
||||||
return (event->type == MapNotify) && (event->xmap.window == (Window)arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void * Jtk_CreateWindow()
|
|
||||||
{
|
|
||||||
XEvent event;
|
|
||||||
Window window = XCreateWindow(g_display,
|
|
||||||
RootWindow(g_display, g_vi->screen),
|
|
||||||
0, 0, 800, 800, 0, g_vi->depth, InputOutput, g_vi->visual,
|
|
||||||
CWBorderPixel | CWColormap | CWEventMask, &g_swa);
|
|
||||||
XMapWindow(g_display, window);
|
|
||||||
XIfEvent(g_display, &event, WaitForNotify, (XPointer)window);
|
|
||||||
if (glXMakeCurrent(g_display, window, g_context) == False)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "glXMakeCurrent() failure\n");
|
|
||||||
XDestroyWindow(g_display, window);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable the window close button. */
|
|
||||||
Atom wm_delete_window_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", False);
|
|
||||||
XSetWMProtocols(g_display, window, &wm_delete_window_atom, 1);
|
|
||||||
|
|
||||||
return (void *)window;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jtk_SwapBuffers(void * window)
|
|
||||||
{
|
|
||||||
glXSwapBuffers(g_display, (Window)window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jtk_CloseWindow(void * window)
|
|
||||||
{
|
|
||||||
XDestroyWindow(g_display, (Window)window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jtk_SetWindowTitle(void * window, const char * title)
|
|
||||||
{
|
|
||||||
XTextProperty title_property;
|
|
||||||
if (XStringListToTextProperty((char **)&title, 1, &title_property) != 0)
|
|
||||||
{
|
|
||||||
XSetTextProperty(g_display, (Window)window, &title_property, XA_WM_NAME);
|
|
||||||
XFree(title_property.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the window icon.
|
|
||||||
*
|
|
||||||
* @param window
|
|
||||||
* The window to operate on.
|
|
||||||
* @param data
|
|
||||||
* The format of data must be 32 bits per pixel in BGRA format (e.g. data[0]
|
|
||||||
* is blue value, data[3] is alpha value of first pixel).
|
|
||||||
* @param width
|
|
||||||
* Icon width.
|
|
||||||
* @param height
|
|
||||||
* Icon height.
|
|
||||||
*/
|
|
||||||
void Jtk_SetWindowIcon(void * window, const uint8_t * data,
|
|
||||||
size_t width, size_t height)
|
|
||||||
{
|
|
||||||
Atom net_wm_icon_atom = XInternAtom(g_display, "_NET_WM_ICON", False);
|
|
||||||
size_t property_size = (2u + width * height) * sizeof(long);
|
|
||||||
unsigned long * property_data = (unsigned long *)malloc(property_size);
|
|
||||||
property_data[0] = width;
|
|
||||||
property_data[1] = height;
|
|
||||||
unsigned long * dest = &property_data[2];
|
|
||||||
const uint32_t * src = (const uint32_t *)data;
|
|
||||||
for (size_t row = 0u; row < height; row++)
|
|
||||||
{
|
|
||||||
for (size_t col = 0u; col < width; col++)
|
|
||||||
{
|
|
||||||
*dest++ = *src++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XChangeProperty(g_display, (Window)window, net_wm_icon_atom, XA_CARDINAL,
|
|
||||||
32, PropModeReplace, (uint8_t *)property_data, property_size);
|
|
||||||
XFlush(g_display);
|
|
||||||
free(property_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,11 +0,0 @@
|
|||||||
#ifndef JTK_WINDOW_H
|
|
||||||
#define JTK_WINDOW_H
|
|
||||||
|
|
||||||
void * Jtk_CreateWindow();
|
|
||||||
void Jtk_SwapBuffers(void * window);
|
|
||||||
void Jtk_CloseWindow(void * window);
|
|
||||||
void Jtk_SetWindowTitle(void * window, const char * title);
|
|
||||||
void Jtk_SetWindowIcon(void * window, const uint8_t * data,
|
|
||||||
size_t width, size_t height);
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
x
Reference in New Issue
Block a user