mirror of
https://git.shylie.info/shylie/glerminal.git
synced 2025-10-20 20:40:19 +00:00
Compare commits
39 Commits
ffcafb5160
...
main
Author | SHA1 | Date | |
---|---|---|---|
fb3eeb6ec9 | |||
263cf68ca2 | |||
b8e616c8d6 | |||
1bfbab7a96 | |||
d156005441 | |||
82389b8c12 | |||
0a9d211942 | |||
937693ce6a | |||
365cad551b | |||
5fbeb1e4e9 | |||
11ffc40bbb | |||
db46885ee9 | |||
20fad92e4f | |||
7c0c02b9af | |||
1a1f4e8b13 | |||
![]() |
6663804c88 | ||
![]() |
9d88ebbb3b | ||
![]() |
76bfd67f4e | ||
![]() |
4811e4d970 | ||
![]() |
e402b5f5a3 | ||
![]() |
139681a3fd | ||
![]() |
45ec13db45 | ||
![]() |
996d14c93c | ||
![]() |
d50fefc359 | ||
![]() |
6444654f42 | ||
![]() |
da1f32a014 | ||
![]() |
71c052b38f | ||
![]() |
a39905c6cb | ||
![]() |
e5b017ad97 | ||
![]() |
fa8b8bfcf8 | ||
![]() |
ca0addb54c | ||
![]() |
93df224dc8 | ||
![]() |
35902c2803 | ||
![]() |
4b740e3edd | ||
![]() |
10a90a5f6a | ||
![]() |
939fea0fa7 | ||
![]() |
844e1b6c7a | ||
![]() |
7cd81b31eb | ||
![]() |
1e0be8eca0 |
@@ -5,20 +5,22 @@ on: push
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-app:
|
build-app:
|
||||||
runs-on: linux_amd64
|
runs-on: shy-server
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout current
|
- name: Checkout current
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
path: curr
|
path: curr
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Checkout previous
|
lfs: true
|
||||||
|
- name: Checkout previous known working
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
path: prev
|
path: prev
|
||||||
fetch-depth: 2
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- run: cd prev && git checkout HEAD^
|
lfs: true
|
||||||
|
- run: cd prev && git checkout 263cf68ca2
|
||||||
- name: Build current
|
- name: Build current
|
||||||
run: cmake -S curr -B curr/build -DGLERMINAL_TEST=ON && cmake --build curr/build
|
run: cmake -S curr -B curr/build -DGLERMINAL_TEST=ON && cmake --build curr/build
|
||||||
- name: Build previous
|
- name: Build previous
|
||||||
@@ -27,7 +29,7 @@ jobs:
|
|||||||
run: cd curr/build/tests && ls $PWD/resources && XDG_RUNTIME_DIR=$PWD xvfb-run -a ./test-basic
|
run: cd curr/build/tests && ls $PWD/resources && XDG_RUNTIME_DIR=$PWD xvfb-run -a ./test-basic
|
||||||
- name: Generate PNG file for previous
|
- name: Generate PNG file for previous
|
||||||
run: cd prev/build/tests && ls $PWD/resources && XDG_RUNTIME_DIR=$PWD xvfb-run -a ./test-basic
|
run: cd prev/build/tests && ls $PWD/resources && XDG_RUNTIME_DIR=$PWD xvfb-run -a ./test-basic
|
||||||
- name: Upload current PNG
|
- name: Upload PNG files
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: basic
|
name: basic
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,4 @@
|
|||||||
build/
|
build/
|
||||||
|
cmake-build-*/
|
||||||
|
.idea/
|
||||||
|
.cache/
|
||||||
|
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
|||||||
[submodule "glfw"]
|
[submodule "glfw"]
|
||||||
path = glfw
|
path = glfw
|
||||||
url = https://git.shylie.info/shylie/glfw.git
|
url = https://github.com/glfw/glfw.git
|
||||||
|
@@ -11,6 +11,7 @@ set(GLERMINAL_GRID_WIDTH 40 CACHE STRING "")
|
|||||||
set(GLERMINAL_GRID_HEIGHT 25 CACHE STRING "")
|
set(GLERMINAL_GRID_HEIGHT 25 CACHE STRING "")
|
||||||
set(GLERMINAL_LAYER_COUNT 64 CACHE STRING "")
|
set(GLERMINAL_LAYER_COUNT 64 CACHE STRING "")
|
||||||
set(GLERMINAL_CELL_SCALE 4 CACHE STRING "")
|
set(GLERMINAL_CELL_SCALE 4 CACHE STRING "")
|
||||||
|
set(GLERMINAL_CELL_SIZE 8 CACHE STRING "")
|
||||||
|
|
||||||
configure_file(source/glerminal-config.h.in glerminal-config.h @ONLY)
|
configure_file(source/glerminal-config.h.in glerminal-config.h @ONLY)
|
||||||
|
|
||||||
@@ -20,12 +21,16 @@ add_library(glerminal STATIC
|
|||||||
${CMAKE_CURRENT_BINARY_DIR}/glerminal-config.h
|
${CMAKE_CURRENT_BINARY_DIR}/glerminal-config.h
|
||||||
include/glerminal.h
|
include/glerminal.h
|
||||||
|
|
||||||
|
source/stb_image.h
|
||||||
source/glerminal-private.h
|
source/glerminal-private.h
|
||||||
source/glerminal.cpp
|
source/glerminal.cpp
|
||||||
|
|
||||||
source/glad/glad.h
|
source/glad/glad.h
|
||||||
source/KHR/khrplatform.h
|
source/KHR/khrplatform.h
|
||||||
source/glad.c
|
source/glad.c
|
||||||
|
|
||||||
|
source/miniaudio.h
|
||||||
|
source/miniaudio.c
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(glerminal
|
set_target_properties(glerminal
|
||||||
@@ -42,7 +47,7 @@ target_include_directories(glerminal
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(glerminal
|
target_link_libraries(glerminal
|
||||||
PRIVATE
|
PUBLIC
|
||||||
glfw
|
glfw
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,13 +59,6 @@ target_compile_definitions(glerminal
|
|||||||
GLERMINAL_VERSION_PATCH=${PROJECT_VERSION_PATCH}
|
GLERMINAL_VERSION_PATCH=${PROJECT_VERSION_PATCH}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (MSVC)
|
|
||||||
target_link_options(glerminal
|
|
||||||
PUBLIC
|
|
||||||
"/ENTRY:mainCRTStartup"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(PROJECT_IS_TOP_LEVEL)
|
if(PROJECT_IS_TOP_LEVEL)
|
||||||
add_subdirectory(examples examples)
|
add_subdirectory(examples examples)
|
||||||
endif()
|
endif()
|
||||||
|
37
PROJECT_RETROSPECTIVE.md
Normal file
37
PROJECT_RETROSPECTIVE.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# A look back on what I learned
|
||||||
|
|
||||||
|
## why?
|
||||||
|
|
||||||
|
I came across an art/rendering style called "sprite stacking".
|
||||||
|
I found sprite stacking very interesting in comparison to traditional methods,
|
||||||
|
and wanted to experiment with the style.
|
||||||
|
|
||||||
|
## challenge
|
||||||
|
|
||||||
|
This was my first big graphics-based project. Computer graphics
|
||||||
|
at the low-level was new to me. I took this as an opportunity to
|
||||||
|
learn the basics of OpenGL. This learning process was the most
|
||||||
|
difficult part of the project, especially the domain-specific
|
||||||
|
rendering techniques used.
|
||||||
|
|
||||||
|
## how?
|
||||||
|
|
||||||
|
I found some [great tutorials](https://learnopengl.com) to get started,
|
||||||
|
and though these helped, I also did a lot of individual
|
||||||
|
learning through experimentation and discussion with peers.
|
||||||
|
|
||||||
|
## results
|
||||||
|
|
||||||
|
In the end, the library had most of the functionality
|
||||||
|
I originally wanted. The library can draw up to 256 layers of icons in a grid,
|
||||||
|
with optional offsets and tints per icon. Here's an example with only 7 library calls:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## evaluation
|
||||||
|
|
||||||
|
Besides learning the basics of OpenGL, I also learned
|
||||||
|
how to use CMake to help build the library. Also, I set up
|
||||||
|
continuous integration for automated testing on a git commit.
|
||||||
|
If I were to rewrite this library, I would definitely invest more
|
||||||
|
into the automated testing process.
|
@@ -1,2 +1,4 @@
|
|||||||
# termg
|
# glerminal
|
||||||
|
|
||||||
|
glerminal is a tile-based graphics library created
|
||||||
|
with the intent to use a sprite-stacking art style.
|
||||||
|
BIN
example.gif
Normal file
BIN
example.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 MiB |
@@ -12,8 +12,10 @@ file(GLOB_RECURSE
|
|||||||
|
|
||||||
foreach(RESOURCE_FILE ${EXAMPLE_RESOURCES})
|
foreach(RESOURCE_FILE ${EXAMPLE_RESOURCES})
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RESOURCE_FILE}
|
OUTPUT
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy
|
${CMAKE_CURRENT_BINARY_DIR}/${RESOURCE_FILE}
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E copy
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_FILE}
|
${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_FILE}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/${RESOURCE_FILE}
|
${CMAKE_CURRENT_BINARY_DIR}/${RESOURCE_FILE}
|
||||||
DEPENDS
|
DEPENDS
|
||||||
|
@@ -9,9 +9,9 @@ namespace
|
|||||||
glerminal_load_sprites_file("resources/atlas.png");
|
glerminal_load_sprites_file("resources/atlas.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainloop(float dt)
|
void mainloop(double dt)
|
||||||
{
|
{
|
||||||
static float time = 1;
|
static double time = 1;
|
||||||
|
|
||||||
time += dt;
|
time += dt;
|
||||||
|
|
||||||
@@ -30,8 +30,8 @@ namespace
|
|||||||
{
|
{
|
||||||
for (int k = 0; k < LAYER_COUNT; k++)
|
for (int k = 0; k < LAYER_COUNT; k++)
|
||||||
{
|
{
|
||||||
glerminal_set(i, j, k, rand() % 4);
|
glerminal_set(i + 1, j + 1, k, rand() % 4);
|
||||||
glerminal_offset(i, j, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32);
|
glerminal_offset(i + 1, j + 1, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,5 +42,5 @@ namespace
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
glerminal_run(init, mainloop);
|
glerminal_run({init, mainloop});
|
||||||
}
|
}
|
@@ -9,25 +9,25 @@ namespace
|
|||||||
{
|
{
|
||||||
glerminal_load_sprites_file("resources/basic.png");
|
glerminal_load_sprites_file("resources/basic.png");
|
||||||
|
|
||||||
for (int i = 0; i < GRID_WIDTH; i++)
|
for (int i = 0; i < GRID_WIDTH + 2; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < GRID_HEIGHT; j++)
|
for (int j = 0; j < GRID_HEIGHT + 2; j++)
|
||||||
{
|
{
|
||||||
glerminal_set(i, j, 0, 1);
|
glerminal_set(i, j, 0, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainloop(float dt)
|
void mainloop(double dt)
|
||||||
{
|
{
|
||||||
static float time = 0;
|
static double time = 0;
|
||||||
|
|
||||||
time += dt;
|
time += dt;
|
||||||
time = fmodf(time, 3.1415926f * 2);
|
time = fmodf(time, 3.1415926f * 2);
|
||||||
|
|
||||||
for (int i = 0; i < GRID_WIDTH; i++)
|
for (int i = 0; i < GRID_WIDTH + 2; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < GRID_HEIGHT; j++)
|
for (int j = 0; j < GRID_HEIGHT + 2; j++)
|
||||||
{
|
{
|
||||||
glerminal_offset(i, j, 0, cosf(time - i / 3.1415f), sinf(time - j / 3.1415f));
|
glerminal_offset(i, j, 0, cosf(time - i / 3.1415f), sinf(time - j / 3.1415f));
|
||||||
}
|
}
|
||||||
@@ -39,5 +39,5 @@ namespace
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
glerminal_run(init, mainloop);
|
glerminal_run({init, mainloop});
|
||||||
}
|
}
|
@@ -18,22 +18,16 @@ namespace
|
|||||||
{
|
{
|
||||||
glerminal_load_sprites_file("resources/rogue.png");
|
glerminal_load_sprites_file("resources/rogue.png");
|
||||||
|
|
||||||
for (int i = 0; i < WALL_LAYERS; i++)
|
for (int i = 0; i < GRID_WIDTH + 2; i++)
|
||||||
{
|
{
|
||||||
const unsigned char v = (i + 1) * (256 / WALL_LAYERS) - 1;
|
for (int j = 0; j < GRID_HEIGHT + 2; j++)
|
||||||
const unsigned int j = (0xFF << 24) | (v << 16) | (v << 8) | v;
|
|
||||||
glerminal_layer_color(i, j);
|
|
||||||
|
|
||||||
glerminal_layer_scale(i, (i / static_cast<float>(WALL_LAYERS)) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < GRID_WIDTH; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < GRID_HEIGHT; j++)
|
|
||||||
{
|
{
|
||||||
for (int k = 0; k < WALL_LAYERS; k++)
|
for (int k = 0; k < WALL_LAYERS; k++)
|
||||||
{
|
{
|
||||||
if (i == 0 || j == 0 || i == GRID_WIDTH - 1 || j == GRID_HEIGHT - 1)
|
const unsigned char v = (k + 1) * (256 / WALL_LAYERS) - 1;
|
||||||
|
const unsigned int c = (0xFF << 24) | (v << 16) | (v << 8) | v;
|
||||||
|
|
||||||
|
if (i == 1 || j == 1 || i == GRID_WIDTH || j == GRID_HEIGHT)
|
||||||
{
|
{
|
||||||
glerminal_set(i, j, k, floor);
|
glerminal_set(i, j, k, floor);
|
||||||
}
|
}
|
||||||
@@ -41,22 +35,25 @@ namespace
|
|||||||
{
|
{
|
||||||
glerminal_set(i, j, k, wall);
|
glerminal_set(i, j, k, wall);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glerminal_color(i, j, k, c);
|
||||||
|
glerminal_scale(i, j, k, (k / static_cast<float>(WALL_LAYERS)) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainloop(float dt)
|
void mainloop(double dt)
|
||||||
{
|
{
|
||||||
static float time = 0;
|
static double time = 0;
|
||||||
time += dt;
|
time += dt;
|
||||||
|
|
||||||
const float cx = GRID_WIDTH / 2.0f * cosf(time / 2) + GRID_WIDTH / 2.0f;
|
const float cx = GRID_WIDTH / 2.0f * cosf(time / 2) + GRID_WIDTH / 2.0f + 0.5f;
|
||||||
const float cy = GRID_HEIGHT / 2.0f * sinf(time / 2) + GRID_HEIGHT / 2.0f;
|
const float cy = GRID_HEIGHT / 2.0f * sinf(time / 2) + GRID_HEIGHT / 2.0f + 0.5f;
|
||||||
|
|
||||||
for (int i = 0; i < GRID_WIDTH; i++)
|
for (int i = 0; i < GRID_WIDTH + 2; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < GRID_HEIGHT; j++)
|
for (int j = 0; j < GRID_HEIGHT + 2; j++)
|
||||||
{
|
{
|
||||||
for (int k = 0; k < WALL_LAYERS; k++)
|
for (int k = 0; k < WALL_LAYERS; k++)
|
||||||
{
|
{
|
||||||
@@ -83,5 +80,5 @@ namespace
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
glerminal_run(init, mainloop);
|
glerminal_run({init, mainloop});
|
||||||
}
|
}
|
@@ -11,40 +11,41 @@ namespace
|
|||||||
|
|
||||||
glerminal_load_sprites_file("resources/towers.png");
|
glerminal_load_sprites_file("resources/towers.png");
|
||||||
|
|
||||||
for (int i = 0; i < LAYER_COUNT; i++)
|
|
||||||
{
|
|
||||||
constexpr unsigned char c = 16;
|
|
||||||
const unsigned char v = (255 - c) * powf((256 / LAYER_COUNT * i - 1) / 256.0f, 2.0f) + c;
|
|
||||||
const unsigned int j = (0xFF << 24) | (v << 16) | (v << 8) | v;
|
|
||||||
glerminal_layer_color(i, j);
|
|
||||||
glerminal_layer_scale(i, i / static_cast<float>(LAYER_COUNT) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < GRID_WIDTH; i++)
|
for (int i = 0; i < GRID_WIDTH + 2; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < GRID_HEIGHT; j++)
|
for (int j = 0; j < GRID_HEIGHT + 2; j++)
|
||||||
{
|
{
|
||||||
const int c = rand() % (LAYER_COUNT * 3 / 4) + LAYER_COUNT / 4;
|
const int c = rand() % (LAYER_COUNT * 3 / 4) + LAYER_COUNT / 4;
|
||||||
for (int k = 0; k < c; k++)
|
for (int k = 0; k < c; k++)
|
||||||
{
|
{
|
||||||
glerminal_set(i, j, k, 1);
|
glerminal_set(i, j, k, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int k = 0; k < LAYER_COUNT; k++)
|
||||||
|
{
|
||||||
|
constexpr unsigned char min = 16;
|
||||||
|
const unsigned char v = (255 - min) * powf((256 / LAYER_COUNT * k - 1) / 256.0f, 2.0f) + min;
|
||||||
|
const unsigned int col = (0xFF << 24) | (v << 16) | (v << 8) | v;
|
||||||
|
glerminal_color(i, j, k, col);
|
||||||
|
glerminal_scale(i, j, k, k / static_cast<float>(LAYER_COUNT) + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainloop(float dt)
|
void mainloop(double dt)
|
||||||
{
|
{
|
||||||
static float time = 0;
|
static double time = 0;
|
||||||
|
|
||||||
time += dt;
|
time += dt;
|
||||||
|
|
||||||
const float cx = (GRID_WIDTH / 2.0f) * cosf(time / 3.1415f) + (GRID_WIDTH / 2.0f);
|
const float cx = (GRID_WIDTH / 2.0f) * cosf(time / 3.1415f) + (GRID_WIDTH / 2.0f) + 0.5f;
|
||||||
const float cy = (GRID_HEIGHT / 2.0f) * sinf(time / 3.1415f) + (GRID_HEIGHT / 2.0f);
|
const float cy = (GRID_HEIGHT / 2.0f) * sinf(time / 3.1415f) + (GRID_HEIGHT / 2.0f) + 0.5f;
|
||||||
|
|
||||||
for (int i = 0; i < GRID_WIDTH; i++)
|
for (int i = 0; i < GRID_WIDTH + 2; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < GRID_WIDTH; j++)
|
for (int j = 0; j < GRID_WIDTH + 2; j++)
|
||||||
{
|
{
|
||||||
for (int k = 0; k < LAYER_COUNT; k++)
|
for (int k = 0; k < LAYER_COUNT; k++)
|
||||||
{
|
{
|
||||||
@@ -63,5 +64,5 @@ namespace
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
glerminal_run(init, mainloop);
|
glerminal_run({init, mainloop});
|
||||||
}
|
}
|
@@ -9,14 +9,24 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef void (*glerminal_init_cb)();
|
typedef void (*glerminal_init_cb)();
|
||||||
typedef void (*glerminal_main_cb)(float dt);
|
typedef void (*glerminal_main_cb)(double dt);
|
||||||
|
typedef void (*glerminal_keys_cb)(int key);
|
||||||
|
typedef void (*glerminal_mousemoved_cb)(double x, double y);
|
||||||
|
typedef void (*glerminal_mousepress_cb)(int button, double x, double y);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
glerminal_init_cb init;
|
||||||
|
glerminal_main_cb main;
|
||||||
|
glerminal_keys_cb keypress, keyrelease;
|
||||||
|
glerminal_mousemoved_cb moved;
|
||||||
|
glerminal_mousepress_cb mousepress, mouserelease;
|
||||||
|
} glerminal_init_params;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Call init once, then run the application's mainloop
|
* @brief Call init once, then run the application's mainloop
|
||||||
* @param init initialization callback
|
* @param params Initialization parameters
|
||||||
* @param main main calllback
|
|
||||||
*/
|
*/
|
||||||
void glerminal_run(glerminal_init_cb init, glerminal_main_cb main);
|
void glerminal_run(glerminal_init_params params);
|
||||||
|
|
||||||
void glerminal_quit();
|
void glerminal_quit();
|
||||||
|
|
||||||
@@ -27,42 +37,46 @@ void glerminal_flush();
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a cell's sprite
|
* @brief Set a cell's sprite
|
||||||
* @param x position of the cell in the range [0, 40)
|
* @param x position of the cell in the range [0, GRID_WIDTH)
|
||||||
* @param y position of the cell in the range [0, 25)
|
* @param y position of the cell in the range [0, GRID_HEIGHT)
|
||||||
* @param layer layer of the cell in the range [0, 8)
|
* @param layer layer of the cell in the range [0, LAYER_COUNT)
|
||||||
* @param sprite sprite's index in the range [0, 256)
|
* @param sprite sprite's index in the range [0, 4096)
|
||||||
*/
|
*/
|
||||||
void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned char sprite);
|
void glerminal_set(int x, int y, int layer, unsigned short sprite);
|
||||||
/**
|
/**
|
||||||
* @brief Get a cell's sprite
|
* @brief Get a cell's sprite
|
||||||
* @param x position of the cell in the range [0, 40)
|
* @param x position of the cell in the range [0, GRID_WIDTH)
|
||||||
* @param y position of the cell in the range [0, 25)
|
* @param y position of the cell in the range [0, GRID_HEIGHT)
|
||||||
* @param layer layer of the cell in the range [0, 8)
|
* @param layer layer of the cell in the range [0, LAYER_COUNT)
|
||||||
* @return sprite index currently assigned to the cell
|
* @return sprite index currently assigned to the cell
|
||||||
*/
|
*/
|
||||||
unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned char layer);
|
unsigned short glerminal_get(int x, int y, int layer);
|
||||||
/**
|
/**
|
||||||
* @brief Set a cell's offset
|
* @brief Set a cell's offset
|
||||||
* @param x position of the cell in the range [0, 40)
|
* @param x position of the cell in the range [0, GRID_WIDTH)
|
||||||
* @param y position of the cell in the range [0, 25)
|
* @param y position of the cell in the range [0, GRID_HEIGHT)
|
||||||
* @param layer layer of the cell in the range [0, 8)
|
* @param layer layer of the cell in the range [0, LAYER_COUNT)
|
||||||
* @param x_offset offset of the cell on the x axis in the range [-128, 127], where 0 is no offset
|
* @param x_offset offset of the cell on the x axis in cells
|
||||||
* @param y_offset offset of the cell on the y axis in the range [-128, 127], where 0 is no offset
|
* @param y_offset offset of the cell on the y axis in cells
|
||||||
*/
|
*/
|
||||||
void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset);
|
void glerminal_offset(int x, int y, int layer, float x_offset, float y_offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a layer's color
|
* @brief Set a cell's color
|
||||||
* @param layer The layer to modify
|
* @param x position of the cell in the range [0, GRID_WIDTH)
|
||||||
|
* @param y position of the cell in the range [0, GRID_HEIGHT)
|
||||||
|
* @param layer layer of the cell in the range [0, LAYER_COUNT)
|
||||||
* @param color The new color
|
* @param color The new color
|
||||||
*/
|
*/
|
||||||
void glerminal_layer_color(unsigned char layer, unsigned int color);
|
void glerminal_color(int x, int y, int layer, unsigned int color);
|
||||||
/**
|
/**
|
||||||
* @brief Set a layer's scale
|
* @brief Set a cell's scale
|
||||||
* @param layer The layer to modify
|
* @param x position of the cell in the range [0, GRID_WIDTH)
|
||||||
|
* @param y position of the cell in the range [0, GRID_HEIGHT)
|
||||||
|
* @param layer layer of the cell in the range [0, LAYER_COUNT)
|
||||||
* @param scale The new scale
|
* @param scale The new scale
|
||||||
*/
|
*/
|
||||||
void glerminal_layer_scale(unsigned char layer, float scale);
|
void glerminal_scale(int x, int y, int layer, float scale);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Load sprites from a png file
|
* @brief Load sprites from a png file
|
||||||
@@ -78,6 +92,8 @@ int glerminal_load_sprites_file(const char* filename);
|
|||||||
*/
|
*/
|
||||||
int glerminal_load_sprites_buffer(unsigned char width, unsigned char height, const unsigned int* buffer);
|
int glerminal_load_sprites_buffer(unsigned char width, unsigned char height, const unsigned int* buffer);
|
||||||
|
|
||||||
|
void glerminal_sound(const char* name);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -16,7 +16,8 @@ enum
|
|||||||
GRID_WIDTH = @GLERMINAL_GRID_WIDTH@,
|
GRID_WIDTH = @GLERMINAL_GRID_WIDTH@,
|
||||||
GRID_HEIGHT = @GLERMINAL_GRID_HEIGHT@,
|
GRID_HEIGHT = @GLERMINAL_GRID_HEIGHT@,
|
||||||
LAYER_COUNT = @GLERMINAL_LAYER_COUNT@,
|
LAYER_COUNT = @GLERMINAL_LAYER_COUNT@,
|
||||||
CELL_SCALE = @GLERMINAL_CELL_SCALE@
|
CELL_SCALE = @GLERMINAL_CELL_SCALE@,
|
||||||
|
CELL_SIZE = @GLERMINAL_CELL_SIZE@
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@@ -2,30 +2,36 @@
|
|||||||
#define GLERMINAL_PRIVATE_H
|
#define GLERMINAL_PRIVATE_H
|
||||||
|
|
||||||
#include "glerminal.h"
|
#include "glerminal.h"
|
||||||
|
#include "miniaudio.h"
|
||||||
|
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <map>
|
||||||
#include <stdexcept>
|
#include <string>
|
||||||
|
|
||||||
namespace glerminal
|
namespace glerminal
|
||||||
{
|
{
|
||||||
constexpr unsigned int CELL_SIZE = 8;
|
constexpr unsigned int MAX_SPRITES_ROW = 64;
|
||||||
|
constexpr unsigned int MAX_SPRITES = MAX_SPRITES_ROW * MAX_SPRITES_ROW;
|
||||||
constexpr unsigned int GRID_WIDTH = ::GRID_WIDTH;
|
constexpr unsigned int GRID_WIDTH = ::GRID_WIDTH;
|
||||||
constexpr unsigned int GRID_HEIGHT = ::GRID_HEIGHT;
|
constexpr unsigned int GRID_HEIGHT = ::GRID_HEIGHT;
|
||||||
constexpr unsigned int LAYER_COUNT = ::LAYER_COUNT;
|
constexpr unsigned int LAYER_COUNT = ::LAYER_COUNT;
|
||||||
constexpr unsigned int CELL_SCALE = ::CELL_SCALE;
|
constexpr unsigned int CELL_SCALE = ::CELL_SCALE;
|
||||||
|
constexpr unsigned int CELL_SIZE = ::CELL_SIZE;
|
||||||
constexpr unsigned int GRID_AREA = GRID_WIDTH * GRID_HEIGHT;
|
constexpr unsigned int GRID_AREA = GRID_WIDTH * GRID_HEIGHT;
|
||||||
constexpr unsigned int SCREEN_WIDTH = GRID_WIDTH * CELL_SIZE * CELL_SCALE;
|
constexpr unsigned int SCREEN_WIDTH = GRID_WIDTH * CELL_SIZE * CELL_SCALE;
|
||||||
constexpr unsigned int SCREEN_HEIGHT = GRID_HEIGHT * CELL_SIZE * CELL_SCALE;
|
constexpr unsigned int SCREEN_HEIGHT = GRID_HEIGHT * CELL_SIZE * CELL_SCALE;
|
||||||
|
constexpr unsigned int SOUND_CHANNELS = 8;
|
||||||
|
|
||||||
|
constexpr unsigned int GRID_AREA_2 = (GRID_WIDTH + 2) * (GRID_HEIGHT + 2);
|
||||||
|
|
||||||
class glerminal
|
class glerminal
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
glerminal(glerminal_init_cb init, glerminal_main_cb main);
|
explicit glerminal(glerminal_init_params params);
|
||||||
~glerminal();
|
~glerminal();
|
||||||
|
|
||||||
glerminal(const glerminal&) = delete;
|
glerminal(const glerminal&) = delete;
|
||||||
@@ -39,12 +45,14 @@ namespace glerminal
|
|||||||
|
|
||||||
void flush();
|
void flush();
|
||||||
|
|
||||||
void set(unsigned char x, unsigned char y, unsigned char layer, unsigned char sprite);
|
void set(int x, int y, int layer, unsigned short sprite);
|
||||||
unsigned char get(unsigned char x, unsigned char y, unsigned char layer) const;
|
unsigned short get(int x, int y, int layer) const;
|
||||||
void offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset);
|
void offset(int x, int y, int layer, float x_offset, float y_offset);
|
||||||
void layer_color(unsigned char layer, unsigned int color);
|
void color(int x, int y, int layer, unsigned int color);
|
||||||
void layer_scale(unsigned char layer, float scale);
|
void scale(int x,int y, int layer, float scale);
|
||||||
void load_atlas(unsigned char w, unsigned char h, const unsigned int* data);
|
void load_atlas(unsigned char w, unsigned char h, const unsigned int* data);
|
||||||
|
bool load_sound(const char* name);
|
||||||
|
void play_sound(const char* name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// glfw data
|
// glfw data
|
||||||
@@ -65,25 +73,26 @@ namespace glerminal
|
|||||||
unsigned int m_framebuffer_backing_texture;
|
unsigned int m_framebuffer_backing_texture;
|
||||||
unsigned int m_screen_framebuffer;
|
unsigned int m_screen_framebuffer;
|
||||||
unsigned int m_screen_framebuffer_backing_texture;
|
unsigned int m_screen_framebuffer_backing_texture;
|
||||||
unsigned int m_layer_colors_buffer;
|
unsigned int m_colors_instance_vbo;
|
||||||
unsigned int m_layer_scales_buffer;
|
unsigned int m_scales_instance_vbo;
|
||||||
unsigned int m_screen_size_uniform_location;
|
|
||||||
unsigned int m_palette_uniform_location;
|
|
||||||
|
|
||||||
// per-cell data
|
// per-cell data
|
||||||
|
|
||||||
unsigned char m_cells[GRID_AREA * LAYER_COUNT];
|
unsigned short m_cells[GRID_AREA_2 * LAYER_COUNT];
|
||||||
float m_offsets[GRID_AREA * LAYER_COUNT * 2];
|
float m_offsets[GRID_AREA_2 * LAYER_COUNT * 2];
|
||||||
|
unsigned char m_colors[GRID_AREA_2 * LAYER_COUNT * 4];
|
||||||
// per-layer data
|
float m_scales[GRID_AREA_2 * LAYER_COUNT];
|
||||||
|
|
||||||
float m_layer_colors[LAYER_COUNT * 4];
|
|
||||||
float m_layer_scales[LAYER_COUNT];
|
|
||||||
|
|
||||||
// library state
|
// library state
|
||||||
|
|
||||||
unsigned int m_sprites[CELL_SIZE * CELL_SIZE * (1 << (8 * sizeof(*m_cells)))];
|
unsigned int m_sprites[(CELL_SIZE + 2) * (CELL_SIZE + 2) * MAX_SPRITES];
|
||||||
glerminal_main_cb m_main;
|
glerminal_main_cb m_main;
|
||||||
|
glerminal_keys_cb m_keypressed, m_keyreleased;
|
||||||
|
glerminal_mousemoved_cb m_mousemoved;
|
||||||
|
glerminal_mousepress_cb m_mousepressed, m_mousereleased;
|
||||||
|
|
||||||
|
ma_engine m_audio_engine;
|
||||||
|
std::map<std::string, ma_sound> m_sounds;
|
||||||
|
|
||||||
#ifdef GLERMINAL_OPENGL_DEBUG_CONTEXT
|
#ifdef GLERMINAL_OPENGL_DEBUG_CONTEXT
|
||||||
mutable std::ofstream m_log;
|
mutable std::ofstream m_log;
|
||||||
@@ -93,12 +102,20 @@ namespace glerminal
|
|||||||
void init_glfw();
|
void init_glfw();
|
||||||
void init_gl();
|
void init_gl();
|
||||||
|
|
||||||
|
void init_audio();
|
||||||
|
|
||||||
void deinit_glfw();
|
void deinit_glfw();
|
||||||
void deinit_gl();
|
void deinit_gl();
|
||||||
|
|
||||||
|
void deinit_audio();
|
||||||
|
|
||||||
void update_sprites();
|
void update_sprites();
|
||||||
void update_layer_colors();
|
void update_colors();
|
||||||
void update_layer_scales();
|
void update_scales();
|
||||||
|
|
||||||
|
static void glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||||
|
static void glfw_mousemoved_handler(GLFWwindow* window, double x, double y);
|
||||||
|
static void glfw_mousepress_handler(GLFWwindow* window, int button, int action, int mods);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,12 +1,14 @@
|
|||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#define STBI_ONLY_PNG
|
#define STBI_ONLY_PNG
|
||||||
#define STBI_MAX_DIMENSIONS 128
|
#define STBI_MAX_DIMENSIONS 2048
|
||||||
#include "glerminal-private.h"
|
#include "glerminal-private.h"
|
||||||
|
|
||||||
#define GRID_SIZE_UNIFORM_NAME "grid_size"
|
#define GRID_SIZE_UNIFORM_NAME "grid_size"
|
||||||
#define SPRITES_UNIFORM_NAME "sprites"
|
#define SPRITES_UNIFORM_NAME "sprites"
|
||||||
#define LAYERS_UNIFORM_NAME "layers"
|
#define LAYERS_UNIFORM_NAME "layers"
|
||||||
#define LAYER_COUNT_UNIFORM_NAME "layer_count"
|
#define LAYER_COUNT_UNIFORM_NAME "layer_count"
|
||||||
|
#define ATLAS_WIDTH_UNIFORM_NAME "atlas_width"
|
||||||
|
#define CELL_SIZE_UNIFORM_NAME "cell_size"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -30,14 +32,15 @@ namespace
|
|||||||
"layout (location = 0) in vec2 position;\n"
|
"layout (location = 0) in vec2 position;\n"
|
||||||
"layout (location = 1) in vec2 offset;\n"
|
"layout (location = 1) in vec2 offset;\n"
|
||||||
"layout (location = 2) in int sprite;\n"
|
"layout (location = 2) in int sprite;\n"
|
||||||
|
"layout (location = 3) in vec4 color;\n"
|
||||||
|
"layout (location = 4) in float scale;\n"
|
||||||
|
"uniform float " CELL_SIZE_UNIFORM_NAME ";\n"
|
||||||
"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n"
|
"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n"
|
||||||
"layout (std430, binding = 0) buffer LayerScales"
|
"uniform int " ATLAS_WIDTH_UNIFORM_NAME ";\n"
|
||||||
"{\n"
|
|
||||||
" float scales[];\n"
|
|
||||||
"} lss;\n"
|
|
||||||
"out VS_OUT {\n"
|
"out VS_OUT {\n"
|
||||||
" flat int sprite;\n"
|
" flat int sprite;\n"
|
||||||
" flat int layer;\n"
|
" flat int layer;\n"
|
||||||
|
" flat vec4 layer_color;\n"
|
||||||
" vec2 texcoord;\n"
|
" vec2 texcoord;\n"
|
||||||
"} vs_out;\n"
|
"} vs_out;\n"
|
||||||
"void main()\n"
|
"void main()\n"
|
||||||
@@ -46,9 +49,10 @@ namespace
|
|||||||
" vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n"
|
" vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n"
|
||||||
" vs_out.sprite = sprite;\n"
|
" vs_out.sprite = sprite;\n"
|
||||||
" vs_out.layer = layer;\n"
|
" vs_out.layer = layer;\n"
|
||||||
" vs_out.texcoord = vec2(position.x + 1, -position.y);\n"
|
" vs_out.layer_color = color;\n"
|
||||||
" vec2 cell_position = vec2(lss.scales[layer] + (gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z));\n"
|
" vs_out.texcoord = vec2(sprite % " ATLAS_WIDTH_UNIFORM_NAME " + position.x + 1, (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ") + vec2(-(2 * position.x + 1) * " GRID_SIZE_UNIFORM_NAME ".z / (2 * " CELL_SIZE_UNIFORM_NAME "), (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / (2 * " CELL_SIZE_UNIFORM_NAME "));\n"
|
||||||
" vec2 temp = ((position + vec2(-0.5, 0.5)) * lss.scales[layer] + cell_position + vec2(0.5, -0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n"
|
" vec2 cell_position = vec2(scale + (gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x));\n"
|
||||||
|
" vec2 temp = ((position + vec2(-0.5, 0.5)) * scale + cell_position + vec2(-0.5, 0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n"
|
||||||
" gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n"
|
" gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
@@ -60,13 +64,14 @@ namespace
|
|||||||
"layout (location = 0) in vec2 position;\n"
|
"layout (location = 0) in vec2 position;\n"
|
||||||
"layout (location = 1) in vec2 offset;\n"
|
"layout (location = 1) in vec2 offset;\n"
|
||||||
"layout (location = 2) in int sprite;\n"
|
"layout (location = 2) in int sprite;\n"
|
||||||
|
"layout (location = 3) in vec4 color;\n"
|
||||||
|
"layout (location = 4) in float scale;\n"
|
||||||
|
"uniform float " CELL_SIZE_UNIFORM_NAME ";\n"
|
||||||
"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n"
|
"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n"
|
||||||
"layout (std430, binding = 0) buffer LayerScales"
|
"uniform int " ATLAS_WIDTH_UNIFORM_NAME ";\n"
|
||||||
"{\n"
|
|
||||||
" float scales[];\n"
|
|
||||||
"} lss;\n"
|
|
||||||
"out VS_OUT {\n"
|
"out VS_OUT {\n"
|
||||||
" flat int sprite;\n"
|
" flat int sprite;\n"
|
||||||
|
" flat vec4 layer_color;\n"
|
||||||
" vec2 texcoord;\n"
|
" vec2 texcoord;\n"
|
||||||
"} vs_out;\n"
|
"} vs_out;\n"
|
||||||
"void main()\n"
|
"void main()\n"
|
||||||
@@ -75,9 +80,10 @@ namespace
|
|||||||
" gl_Layer = layer;\n"
|
" gl_Layer = layer;\n"
|
||||||
" vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n"
|
" vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n"
|
||||||
" vs_out.sprite = sprite;\n"
|
" vs_out.sprite = sprite;\n"
|
||||||
" vs_out.texcoord = vec2(position.x + 1, -position.y);\n"
|
" vs_out.texcoord = vec2(sprite % " ATLAS_WIDTH_UNIFORM_NAME " + position.x + 1, (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ") + vec2(-(2 * position.x + 1) * " GRID_SIZE_UNIFORM_NAME ".z / (2 * " CELL_SIZE_UNIFORM_NAME "), (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / (2 * " CELL_SIZE_UNIFORM_NAME "));\n"
|
||||||
" vec2 cell_position = vec2(lss.scales[layer] + (gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z));\n"
|
" vs_out.layer_color = color;\n"
|
||||||
" vec2 temp = ((position + vec2(-0.5, 0.5)) * lss.scales[layer] + cell_position + vec2(0.5, -0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n"
|
" vec2 cell_position = vec2(scale + (gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x));\n"
|
||||||
|
" vec2 temp = ((position + vec2(-0.5, 0.5)) * scale + cell_position + vec2(-0.5, 0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n"
|
||||||
" gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n"
|
" gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
@@ -91,25 +97,30 @@ namespace
|
|||||||
"in VS_OUT {\n"
|
"in VS_OUT {\n"
|
||||||
" flat int sprite;\n"
|
" flat int sprite;\n"
|
||||||
" flat int layer;\n"
|
" flat int layer;\n"
|
||||||
|
" flat vec4 layer_color;\n"
|
||||||
" vec2 texcoord;\n"
|
" vec2 texcoord;\n"
|
||||||
"} gs_in[];\n"
|
"} gs_in[];\n"
|
||||||
"flat out int sprite;\n"
|
"flat out int sprite;\n"
|
||||||
|
"flat out vec4 layer_color;\n"
|
||||||
"out vec2 texcoord;\n"
|
"out vec2 texcoord;\n"
|
||||||
"void main()\n"
|
"void main()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" gl_Layer = gs_in[0].layer;\n"
|
" gl_Layer = gs_in[0].layer;\n"
|
||||||
" gl_Position = gl_in[0].gl_Position;\n"
|
" gl_Position = gl_in[0].gl_Position;\n"
|
||||||
" sprite = gs_in[0].sprite;\n"
|
" sprite = gs_in[0].sprite;\n"
|
||||||
|
" layer_color = gs_in[0].layer_color;\n"
|
||||||
" texcoord = gs_in[0].texcoord;\n"
|
" texcoord = gs_in[0].texcoord;\n"
|
||||||
" EmitVertex();\n"
|
" EmitVertex();\n"
|
||||||
" gl_Layer = gs_in[1].layer;\n"
|
" gl_Layer = gs_in[1].layer;\n"
|
||||||
" gl_Position = gl_in[1].gl_Position;\n"
|
" gl_Position = gl_in[1].gl_Position;\n"
|
||||||
" sprite = gs_in[1].sprite;\n"
|
" sprite = gs_in[1].sprite;\n"
|
||||||
|
" layer_color = gs_in[1].layer_color;\n"
|
||||||
" texcoord = gs_in[1].texcoord;\n"
|
" texcoord = gs_in[1].texcoord;\n"
|
||||||
" EmitVertex();\n"
|
" EmitVertex();\n"
|
||||||
" gl_Layer = gs_in[2].layer;\n"
|
" gl_Layer = gs_in[2].layer;\n"
|
||||||
" gl_Position = gl_in[2].gl_Position;\n"
|
" gl_Position = gl_in[2].gl_Position;\n"
|
||||||
" sprite = gs_in[2].sprite;\n"
|
" sprite = gs_in[2].sprite;\n"
|
||||||
|
" layer_color = gs_in[2].layer_color;\n"
|
||||||
" texcoord = gs_in[2].texcoord;\n"
|
" texcoord = gs_in[2].texcoord;\n"
|
||||||
" EmitVertex();\n"
|
" EmitVertex();\n"
|
||||||
" EndPrimitive();\n"
|
" EndPrimitive();\n"
|
||||||
@@ -119,13 +130,14 @@ namespace
|
|||||||
|
|
||||||
constexpr char FRAGMENT_SHADER_SOURCE[] =
|
constexpr char FRAGMENT_SHADER_SOURCE[] =
|
||||||
"#version 450 core\n"
|
"#version 450 core\n"
|
||||||
"in vec2 texcoord;\n"
|
|
||||||
"flat in int sprite;\n"
|
"flat in int sprite;\n"
|
||||||
"layout (binding = 0) uniform sampler2DArray " SPRITES_UNIFORM_NAME ";\n"
|
"flat vec4 layer_color;\n"
|
||||||
|
"in vec2 texcoord;\n"
|
||||||
|
"layout (binding = 2) uniform sampler2D " SPRITES_UNIFORM_NAME ";\n"
|
||||||
"out vec4 FragColor;\n"
|
"out vec4 FragColor;\n"
|
||||||
"void main()\n"
|
"void main()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" FragColor = texture(" SPRITES_UNIFORM_NAME ", vec3(texcoord, sprite));\n"
|
" FragColor = layer_color * texture(" SPRITES_UNIFORM_NAME ", texcoord);\n"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
// note: AMD_vertex_shader_layer support required
|
// note: AMD_vertex_shader_layer support required
|
||||||
@@ -133,13 +145,14 @@ namespace
|
|||||||
"#version 450 core\n"
|
"#version 450 core\n"
|
||||||
"in VS_OUT {\n"
|
"in VS_OUT {\n"
|
||||||
" flat int sprite;\n"
|
" flat int sprite;\n"
|
||||||
|
" flat vec4 layer_color;\n"
|
||||||
" vec2 texcoord;\n"
|
" vec2 texcoord;\n"
|
||||||
"} fs_in;\n"
|
"} fs_in;\n"
|
||||||
"layout (binding = 0) uniform sampler2DArray " SPRITES_UNIFORM_NAME ";\n"
|
"layout (binding = 2) uniform sampler2D " SPRITES_UNIFORM_NAME ";\n"
|
||||||
"out vec4 FragColor;\n"
|
"out vec4 FragColor;\n"
|
||||||
"void main()\n"
|
"void main()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" FragColor = texture(" SPRITES_UNIFORM_NAME ", vec3(fs_in.texcoord, fs_in.sprite));\n"
|
" FragColor = fs_in.layer_color * texture(" SPRITES_UNIFORM_NAME ", fs_in.texcoord);\n"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
constexpr const char* FRAGMENT_SHADER_SOURCE_PTR = FRAGMENT_SHADER_SOURCE;
|
constexpr const char* FRAGMENT_SHADER_SOURCE_PTR = FRAGMENT_SHADER_SOURCE;
|
||||||
@@ -161,10 +174,6 @@ namespace
|
|||||||
"#version 450 core\n"
|
"#version 450 core\n"
|
||||||
"in vec2 texcoord;\n"
|
"in vec2 texcoord;\n"
|
||||||
"layout (binding = 1) uniform sampler2DArray " LAYERS_UNIFORM_NAME ";\n"
|
"layout (binding = 1) uniform sampler2DArray " LAYERS_UNIFORM_NAME ";\n"
|
||||||
"layout (std430, binding = 1) buffer LayerColors"
|
|
||||||
"{\n"
|
|
||||||
" vec4 colors[];\n"
|
|
||||||
"} lcs;\n"
|
|
||||||
"uniform int " LAYER_COUNT_UNIFORM_NAME ";\n"
|
"uniform int " LAYER_COUNT_UNIFORM_NAME ";\n"
|
||||||
"out vec4 FragColor;\n"
|
"out vec4 FragColor;\n"
|
||||||
"void main()\n"
|
"void main()\n"
|
||||||
@@ -172,7 +181,7 @@ namespace
|
|||||||
" vec3 current_color = vec3(0);\n"
|
" vec3 current_color = vec3(0);\n"
|
||||||
" for (int i = 0; i < " LAYER_COUNT_UNIFORM_NAME "; i++)\n"
|
" for (int i = 0; i < " LAYER_COUNT_UNIFORM_NAME "; i++)\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" vec4 texsample = lcs.colors[i] * texture(" LAYERS_UNIFORM_NAME ", vec3(texcoord, i));\n"
|
" vec4 texsample = texture(" LAYERS_UNIFORM_NAME ", vec3(texcoord, i));\n"
|
||||||
" current_color = mix(current_color, texsample.rgb, texsample.a);\n"
|
" current_color = mix(current_color, texsample.rgb, texsample.a);\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" FragColor = vec4(current_color, 1);\n"
|
" FragColor = vec4(current_color, 1);\n"
|
||||||
@@ -183,13 +192,18 @@ namespace
|
|||||||
|
|
||||||
namespace glerminal
|
namespace glerminal
|
||||||
{
|
{
|
||||||
glerminal::glerminal(glerminal_init_cb init, glerminal_main_cb main) :
|
glerminal::glerminal(glerminal_init_params params) :
|
||||||
m_main(main),
|
m_main(params.main),
|
||||||
|
m_keypressed(params.keypress),
|
||||||
|
m_keyreleased(params.keyrelease),
|
||||||
|
m_mousemoved(params.moved),
|
||||||
|
m_mousepressed(params.mousepress),
|
||||||
|
m_mousereleased(params.mouserelease),
|
||||||
m_cells{ },
|
m_cells{ },
|
||||||
m_offsets{ },
|
m_offsets{ },
|
||||||
m_sprites{ },
|
m_sprites{ },
|
||||||
m_layer_colors{ },
|
m_colors{ },
|
||||||
m_layer_scales{ }
|
m_scales{ }
|
||||||
#ifdef GLERMINAL_OPENGL_DEBUG_CONTEXT
|
#ifdef GLERMINAL_OPENGL_DEBUG_CONTEXT
|
||||||
, m_log("log.txt")
|
, m_log("log.txt")
|
||||||
#endif
|
#endif
|
||||||
@@ -200,7 +214,7 @@ namespace glerminal
|
|||||||
}
|
}
|
||||||
|
|
||||||
// unsure if this should be an error
|
// unsure if this should be an error
|
||||||
if (!init)
|
if (!params.init)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("No init callback provided.");
|
throw std::runtime_error("No init callback provided.");
|
||||||
}
|
}
|
||||||
@@ -210,22 +224,24 @@ namespace glerminal
|
|||||||
throw std::runtime_error("No main callback provided.");
|
throw std::runtime_error("No main callback provided.");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < LAYER_COUNT; i++)
|
for (int i = 0; i < GRID_AREA_2 * LAYER_COUNT; i++)
|
||||||
{
|
{
|
||||||
m_layer_colors[i * 4 + 0] = m_layer_colors[i * 4 + 1] = m_layer_colors[i * 4 + 2] = m_layer_colors[i * 4 + 3] = 1;
|
m_colors[i * 4 + 0] = m_colors[i * 4 + 1] = m_colors[i * 4 + 2] = m_colors[i * 4 + 3] = 255;
|
||||||
m_layer_scales[i] = 1;
|
m_scales[i] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_glfw();
|
init_glfw();
|
||||||
init_gl();
|
init_gl();
|
||||||
|
init_audio();
|
||||||
|
|
||||||
GLERMINAL_G = this;
|
GLERMINAL_G = this;
|
||||||
|
|
||||||
init();
|
params.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
glerminal::~glerminal()
|
glerminal::~glerminal()
|
||||||
{
|
{
|
||||||
|
deinit_audio();
|
||||||
deinit_gl();
|
deinit_gl();
|
||||||
deinit_glfw();
|
deinit_glfw();
|
||||||
|
|
||||||
@@ -234,12 +250,12 @@ namespace glerminal
|
|||||||
|
|
||||||
void glerminal::run()
|
void glerminal::run()
|
||||||
{
|
{
|
||||||
float last = glfwGetTime();
|
double last = glfwGetTime();
|
||||||
while (!glfwWindowShouldClose(m_window))
|
while (!glfwWindowShouldClose(m_window))
|
||||||
{
|
{
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
const float current = glfwGetTime();
|
const double current = glfwGetTime();
|
||||||
|
|
||||||
m_main(current - last);
|
m_main(current - last);
|
||||||
|
|
||||||
@@ -254,17 +270,17 @@ namespace glerminal
|
|||||||
|
|
||||||
void glerminal::flush()
|
void glerminal::flush()
|
||||||
{
|
{
|
||||||
glNamedBufferData(m_sprites_instance_vbo, sizeof(m_cells), m_cells, GL_STREAM_DRAW);
|
glNamedBufferSubData(m_sprites_instance_vbo, 0, sizeof(m_cells), m_cells);
|
||||||
glNamedBufferData(m_offsets_instance_vbo, sizeof(m_offsets), m_offsets, GL_STREAM_DRAW);
|
glNamedBufferSubData(m_offsets_instance_vbo, 0, sizeof(m_offsets), m_offsets);
|
||||||
update_sprites();
|
update_sprites();
|
||||||
update_layer_colors();
|
update_colors();
|
||||||
update_layer_scales();
|
update_scales();
|
||||||
|
|
||||||
glUseProgram(m_program);
|
glUseProgram(m_program);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
|
||||||
glBindVertexArray(m_vao);
|
glBindVertexArray(m_vao);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_AREA * LAYER_COUNT);
|
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_AREA_2 * LAYER_COUNT);
|
||||||
|
|
||||||
glUseProgram(m_screen_program);
|
glUseProgram(m_screen_program);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, m_screen_framebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, m_screen_framebuffer);
|
||||||
@@ -272,24 +288,25 @@ namespace glerminal
|
|||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glBlitNamedFramebuffer(m_screen_framebuffer, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
glBlitNamedFramebuffer(m_screen_framebuffer, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
|
|
||||||
glfwSwapBuffers(m_window);
|
glfwSwapBuffers(m_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal::set(unsigned char x, unsigned char y, unsigned char layer, unsigned char sprite)
|
void glerminal::set(int x, int y, int layer, unsigned short sprite)
|
||||||
{
|
{
|
||||||
if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT)
|
if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT)
|
||||||
{
|
{
|
||||||
m_cells[x + y * GRID_WIDTH + layer * GRID_AREA] = sprite;
|
m_cells[x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2] = sprite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char glerminal::get(unsigned char x, unsigned char y, unsigned char layer) const
|
unsigned short glerminal::get(int x, int y, int layer) const
|
||||||
{
|
{
|
||||||
if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT)
|
if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT)
|
||||||
{
|
{
|
||||||
return m_cells[x + y * GRID_WIDTH + layer * GRID_AREA];
|
return m_cells[x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -297,50 +314,93 @@ namespace glerminal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal::offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset)
|
void glerminal::offset(int x, int y, int layer, float x_offset, float y_offset)
|
||||||
{
|
{
|
||||||
if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT)
|
if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT)
|
||||||
{
|
{
|
||||||
m_offsets[2 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 0] = x_offset;
|
m_offsets[2 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 0] = x_offset;
|
||||||
m_offsets[2 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 1] = y_offset;
|
m_offsets[2 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 1] = y_offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal::layer_color(unsigned char layer, unsigned int color)
|
void glerminal::color(int x, int y, int layer, unsigned int color)
|
||||||
{
|
{
|
||||||
m_layer_colors[layer * 4 + 0] = ((color >> 0) & 0xFF) / 255.0f;
|
if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT)
|
||||||
m_layer_colors[layer * 4 + 1] = ((color >> 8) & 0xFF) / 255.0f;
|
{
|
||||||
m_layer_colors[layer * 4 + 2] = ((color >> 16) & 0xFF) / 255.0f;
|
m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 0] = (color >> 0) & 0xFF;
|
||||||
m_layer_colors[layer * 4 + 3] = ((color >> 24) & 0xFF) / 255.0f;
|
m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 1] = (color >> 8) & 0xFF;
|
||||||
|
m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 2] = (color >> 16) & 0xFF;
|
||||||
|
m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 3] = (color >> 24) & 0xFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal::layer_scale(unsigned char layer, float scale)
|
void glerminal::scale(int x, int y, int layer, float scale)
|
||||||
{
|
{
|
||||||
m_layer_scales[layer] = scale;
|
if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT)
|
||||||
|
{
|
||||||
|
m_scales[x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2] = scale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal::load_atlas(unsigned char w, unsigned char h, const unsigned int* data)
|
void glerminal::load_atlas(unsigned char w, unsigned char h, const unsigned int* data)
|
||||||
{
|
{
|
||||||
// each row of the atlas
|
for (int src_atlas_row = 0; src_atlas_row < h; src_atlas_row++)
|
||||||
for (int j = 0; j < h; j++)
|
|
||||||
{
|
{
|
||||||
// each column of the atlas
|
for (int src_atlas_col = 0; src_atlas_col < w; src_atlas_col++)
|
||||||
for (int i = 0; i < w; i++)
|
|
||||||
{
|
{
|
||||||
// each row of the individual sprite
|
for (int sprite_row = 0; sprite_row < CELL_SIZE; sprite_row++)
|
||||||
for (int k = 0; k < CELL_SIZE; k++)
|
|
||||||
{
|
{
|
||||||
// offset from base address in atlas layout
|
const unsigned int sprite_index = src_atlas_col + src_atlas_row * w;
|
||||||
const unsigned int src_offset = i + k * w + j * w * CELL_SIZE;
|
const unsigned int dst_atlas_row = sprite_index / MAX_SPRITES_ROW;
|
||||||
// offset from base address in array layout
|
const unsigned int dst_atlas_col = sprite_index % MAX_SPRITES_ROW;
|
||||||
const unsigned int dst_offset = k + i * CELL_SIZE + j * w * CELL_SIZE;
|
|
||||||
|
|
||||||
memcpy(m_sprites + CELL_SIZE * dst_offset, data + CELL_SIZE * src_offset, CELL_SIZE * sizeof(unsigned int));
|
// offset from base address in source atlas layout
|
||||||
|
const unsigned int src_offset = CELL_SIZE * (src_atlas_col + sprite_row * w + src_atlas_row * w * CELL_SIZE);
|
||||||
|
|
||||||
|
const unsigned int dst_column = dst_atlas_col * (CELL_SIZE + 2) + 1;
|
||||||
|
const unsigned int dst_row = MAX_SPRITES_ROW * (CELL_SIZE + 2) * ((sprite_row + 1) + dst_atlas_row * (CELL_SIZE + 2));
|
||||||
|
// offset from base address in glerminal atlas layout
|
||||||
|
const unsigned int dst_offset = dst_column + dst_row;
|
||||||
|
|
||||||
|
memcpy(m_sprites + dst_offset, data + src_offset, CELL_SIZE * sizeof(unsigned int));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool glerminal::load_sound(const char* name)
|
||||||
|
{
|
||||||
|
if (m_sounds.find(name) == m_sounds.end())
|
||||||
|
{
|
||||||
|
ma_sound& ref = m_sounds[name];
|
||||||
|
const ma_result result = ma_sound_init_from_file(
|
||||||
|
&m_audio_engine,
|
||||||
|
name,
|
||||||
|
MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_NO_SPATIALIZATION,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
&ref
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != MA_SUCCESS)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void glerminal::play_sound(const char* name)
|
||||||
|
{
|
||||||
|
load_sound(name);
|
||||||
|
const ma_result result = ma_engine_play_sound(&m_audio_engine, name, nullptr);
|
||||||
|
if (result != MA_SUCCESS)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void glerminal::init_glfw()
|
void glerminal::init_glfw()
|
||||||
{
|
{
|
||||||
glfwInit();
|
glfwInit();
|
||||||
@@ -364,6 +424,11 @@ namespace glerminal
|
|||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to create glerminal window.");
|
throw std::runtime_error("Failed to create glerminal window.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glfwSetWindowUserPointer(m_window, this);
|
||||||
|
glfwSetKeyCallback(m_window, glfw_key_handler);
|
||||||
|
glfwSetCursorPosCallback(m_window, glfw_mousemoved_handler);
|
||||||
|
glfwSetMouseButtonCallback(m_window, glfw_mousepress_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal::log(GLenum type, GLuint id, GLenum severity, const char* message) const
|
void glerminal::log(GLenum type, GLuint id, GLenum severity, const char* message) const
|
||||||
@@ -376,7 +441,6 @@ namespace glerminal
|
|||||||
void glerminal::init_gl()
|
void glerminal::init_gl()
|
||||||
{
|
{
|
||||||
glfwMakeContextCurrent(m_window);
|
glfwMakeContextCurrent(m_window);
|
||||||
glfwSwapInterval(1);
|
|
||||||
|
|
||||||
if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)))
|
if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)))
|
||||||
{
|
{
|
||||||
@@ -451,8 +515,8 @@ namespace glerminal
|
|||||||
glGenBuffers(1, &m_vbo);
|
glGenBuffers(1, &m_vbo);
|
||||||
glGenBuffers(1, &m_sprites_instance_vbo);
|
glGenBuffers(1, &m_sprites_instance_vbo);
|
||||||
glGenBuffers(1, &m_offsets_instance_vbo);
|
glGenBuffers(1, &m_offsets_instance_vbo);
|
||||||
glGenBuffers(1, &m_layer_colors_buffer);
|
glGenBuffers(1, &m_colors_instance_vbo);
|
||||||
glGenBuffers(1, &m_layer_scales_buffer);
|
glGenBuffers(1, &m_scales_instance_vbo);
|
||||||
|
|
||||||
// create vertex array object
|
// create vertex array object
|
||||||
glGenVertexArrays(1, &m_vao);
|
glGenVertexArrays(1, &m_vao);
|
||||||
@@ -460,23 +524,35 @@ namespace glerminal
|
|||||||
|
|
||||||
// set up static vertex attributes
|
// set up static vertex attributes
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(VBO_VERTICES), VBO_VERTICES, GL_STATIC_DRAW);
|
glBufferStorage(GL_ARRAY_BUFFER, sizeof(VBO_VERTICES), VBO_VERTICES, GL_NONE);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(*VBO_VERTICES), reinterpret_cast<void*>(0));
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(*VBO_VERTICES), reinterpret_cast<void*>(0));
|
||||||
|
|
||||||
// set up instanced vertex attributes
|
// set up instanced vertex attributes
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_offsets_instance_vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, m_offsets_instance_vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(m_offsets), m_offsets, GL_STREAM_DRAW);
|
glBufferStorage(GL_ARRAY_BUFFER, sizeof(m_offsets), m_offsets, GL_DYNAMIC_STORAGE_BIT);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(*m_offsets), reinterpret_cast<void*>(0));
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(*m_offsets), reinterpret_cast<void*>(0));
|
||||||
glVertexAttribDivisor(1, 1);
|
glVertexAttribDivisor(1, 1);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_sprites_instance_vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, m_sprites_instance_vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(m_cells), m_cells, GL_STREAM_DRAW);
|
glBufferStorage(GL_ARRAY_BUFFER, sizeof(m_cells), m_cells, GL_DYNAMIC_STORAGE_BIT);
|
||||||
glEnableVertexAttribArray(2);
|
glEnableVertexAttribArray(2);
|
||||||
glVertexAttribIPointer(2, 1, GL_UNSIGNED_BYTE, 1 * sizeof(*m_cells), reinterpret_cast<void*>(0));
|
glVertexAttribIPointer(2, 1, GL_UNSIGNED_SHORT, 1 * sizeof(*m_cells), reinterpret_cast<void*>(0));
|
||||||
glVertexAttribDivisor(2, 1);
|
glVertexAttribDivisor(2, 1);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, m_colors_instance_vbo);
|
||||||
|
glBufferStorage(GL_ARRAY_BUFFER, sizeof(m_colors), m_colors, GL_DYNAMIC_STORAGE_BIT);
|
||||||
|
glEnableVertexAttribArray(3);
|
||||||
|
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 4 * sizeof(*m_colors), reinterpret_cast<void*>(0));
|
||||||
|
glVertexAttribDivisor(3, 1);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, m_scales_instance_vbo);
|
||||||
|
glBufferStorage(GL_ARRAY_BUFFER, sizeof(m_scales), m_scales, GL_DYNAMIC_STORAGE_BIT);
|
||||||
|
glEnableVertexAttribArray(4);
|
||||||
|
glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, 1 * sizeof(*m_scales), reinterpret_cast<void*>(0));
|
||||||
|
glVertexAttribDivisor(4, 1);
|
||||||
|
|
||||||
// set up static vertex attributes
|
// set up static vertex attributes
|
||||||
glGenVertexArrays(1, &m_screen_vao);
|
glGenVertexArrays(1, &m_screen_vao);
|
||||||
glBindVertexArray(m_screen_vao);
|
glBindVertexArray(m_screen_vao);
|
||||||
@@ -487,14 +563,6 @@ namespace glerminal
|
|||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_layer_scales_buffer);
|
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_layer_scales), m_layer_scales, GL_DYNAMIC_READ);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_layer_scales_buffer);
|
|
||||||
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_layer_colors_buffer);
|
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_layer_colors), m_layer_colors, GL_DYNAMIC_READ);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_layer_colors_buffer);
|
|
||||||
|
|
||||||
// -- setup shader program --
|
// -- setup shader program --
|
||||||
// test for features
|
// test for features
|
||||||
const bool vertex_shader_layer_supported =
|
const bool vertex_shader_layer_supported =
|
||||||
@@ -527,8 +595,8 @@ namespace glerminal
|
|||||||
glDeleteShader(geometry_shader);
|
glDeleteShader(geometry_shader);
|
||||||
glDeleteShader(fragment_shader);
|
glDeleteShader(fragment_shader);
|
||||||
|
|
||||||
log(GL_DEBUG_TYPE_ERROR, 0, 0, "Could not compile vertex shader.");
|
log(GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Could not compile vertex shader.");
|
||||||
log(GL_DEBUG_TYPE_ERROR, 0, 0, info_log);
|
log(GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, info_log);
|
||||||
throw std::runtime_error("Could not compile vertex shader.");
|
throw std::runtime_error("Could not compile vertex shader.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,8 +609,8 @@ namespace glerminal
|
|||||||
glDeleteShader(geometry_shader);
|
glDeleteShader(geometry_shader);
|
||||||
glDeleteShader(fragment_shader);
|
glDeleteShader(fragment_shader);
|
||||||
|
|
||||||
log(GL_DEBUG_TYPE_ERROR, 1, 0, "Could not compile geometry shader.");
|
log(GL_DEBUG_TYPE_ERROR, 1, GL_DEBUG_SEVERITY_HIGH, "Could not compile geometry shader.");
|
||||||
log(GL_DEBUG_TYPE_ERROR, 1, 0, info_log);
|
log(GL_DEBUG_TYPE_ERROR, 1, GL_DEBUG_SEVERITY_HIGH, info_log);
|
||||||
throw std::runtime_error("Could not compile geometry shader.");
|
throw std::runtime_error("Could not compile geometry shader.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,8 +623,8 @@ namespace glerminal
|
|||||||
glDeleteShader(geometry_shader);
|
glDeleteShader(geometry_shader);
|
||||||
glDeleteShader(fragment_shader);
|
glDeleteShader(fragment_shader);
|
||||||
|
|
||||||
log(GL_DEBUG_TYPE_ERROR, 2, 0, "Could not compile fragment shader.");
|
log(GL_DEBUG_TYPE_ERROR, 2, GL_DEBUG_SEVERITY_HIGH, "Could not compile fragment shader.");
|
||||||
log(GL_DEBUG_TYPE_ERROR, 2, 0, info_log);
|
log(GL_DEBUG_TYPE_ERROR, 2, GL_DEBUG_SEVERITY_HIGH, info_log);
|
||||||
throw std::runtime_error("Could not compile fragment shader.");
|
throw std::runtime_error("Could not compile fragment shader.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,16 +650,16 @@ namespace glerminal
|
|||||||
|
|
||||||
glDeleteProgram(m_program);
|
glDeleteProgram(m_program);
|
||||||
|
|
||||||
log(GL_DEBUG_TYPE_ERROR, 3, 0, "Could not link shader program.");
|
log(GL_DEBUG_TYPE_ERROR, 3, GL_DEBUG_SEVERITY_HIGH, "Could not link shader program.");
|
||||||
log(GL_DEBUG_TYPE_ERROR, 3, 0, info_log);
|
log(GL_DEBUG_TYPE_ERROR, 3, GL_DEBUG_SEVERITY_HIGH, info_log);
|
||||||
throw std::runtime_error("Could not link shader program.");
|
throw std::runtime_error("Could not link shader program.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup uniforms
|
// setup uniforms
|
||||||
m_screen_size_uniform_location = glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME);
|
|
||||||
|
|
||||||
glUseProgram(m_program);
|
glUseProgram(m_program);
|
||||||
glUniform4f(m_screen_size_uniform_location, GRID_WIDTH, GRID_AREA, 1.0f / GRID_WIDTH, 1.0f / GRID_HEIGHT);
|
glUniform1f(glGetUniformLocation(m_program, CELL_SIZE_UNIFORM_NAME), CELL_SIZE);
|
||||||
|
glUniform4f(glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME), GRID_WIDTH + 2, GRID_AREA_2, 1.0f / GRID_WIDTH, 1.0f / GRID_HEIGHT);
|
||||||
|
glUniform1i(glGetUniformLocation(m_program, ATLAS_WIDTH_UNIFORM_NAME), MAX_SPRITES_ROW);
|
||||||
|
|
||||||
// compile
|
// compile
|
||||||
const unsigned int screen_vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
const unsigned int screen_vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
@@ -611,8 +679,8 @@ namespace glerminal
|
|||||||
glDeleteShader(screen_vertex_shader);
|
glDeleteShader(screen_vertex_shader);
|
||||||
glDeleteShader(screen_fragment_shader);
|
glDeleteShader(screen_fragment_shader);
|
||||||
|
|
||||||
log(GL_DEBUG_TYPE_ERROR, 4, 0, "Could not compile screen vertex shader.");
|
log(GL_DEBUG_TYPE_ERROR, 4, GL_DEBUG_SEVERITY_HIGH, "Could not compile screen vertex shader.");
|
||||||
log(GL_DEBUG_TYPE_ERROR, 4, 0, info_log);
|
log(GL_DEBUG_TYPE_ERROR, 4, GL_DEBUG_SEVERITY_HIGH, info_log);
|
||||||
throw std::runtime_error("Could not compile screen vertex shader.");
|
throw std::runtime_error("Could not compile screen vertex shader.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,8 +692,8 @@ namespace glerminal
|
|||||||
glDeleteShader(screen_vertex_shader);
|
glDeleteShader(screen_vertex_shader);
|
||||||
glDeleteShader(screen_fragment_shader);
|
glDeleteShader(screen_fragment_shader);
|
||||||
|
|
||||||
log(GL_DEBUG_TYPE_ERROR, 5, 0, "Could not compile screen fragment shader.");
|
log(GL_DEBUG_TYPE_ERROR, 5, GL_DEBUG_SEVERITY_HIGH, "Could not compile screen fragment shader.");
|
||||||
log(GL_DEBUG_TYPE_ERROR, 5, 0, info_log);
|
log(GL_DEBUG_TYPE_ERROR, 5, GL_DEBUG_SEVERITY_HIGH, info_log);
|
||||||
throw std::runtime_error("Could not compile screen fragment shader.");
|
throw std::runtime_error("Could not compile screen fragment shader.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,8 +711,8 @@ namespace glerminal
|
|||||||
{
|
{
|
||||||
glDeleteProgram(m_screen_program);
|
glDeleteProgram(m_screen_program);
|
||||||
|
|
||||||
log(GL_DEBUG_TYPE_ERROR, 6, 0, "Could not link screen shader program.");
|
log(GL_DEBUG_TYPE_ERROR, 6, GL_DEBUG_SEVERITY_HIGH, "Could not link screen shader program.");
|
||||||
log(GL_DEBUG_TYPE_ERROR, 6, 0, info_log);
|
log(GL_DEBUG_TYPE_ERROR, 6, GL_DEBUG_SEVERITY_HIGH, info_log);
|
||||||
throw std::runtime_error("Could not link screen shader program.");
|
throw std::runtime_error("Could not link screen shader program.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,20 +723,22 @@ namespace glerminal
|
|||||||
|
|
||||||
// -- setup textures --
|
// -- setup textures --
|
||||||
glGenTextures(1, &m_sprites_texture);
|
glGenTextures(1, &m_sprites_texture);
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_sprites_texture);
|
glBindTexture(GL_TEXTURE_2D, m_sprites_texture);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 0);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
|
||||||
|
glTextureStorage2D(m_sprites_texture, 1, GL_RGBA8, MAX_SPRITES_ROW * (CELL_SIZE + 2), MAX_SPRITES_ROW * (CELL_SIZE + 2));
|
||||||
|
|
||||||
update_sprites();
|
update_sprites();
|
||||||
|
|
||||||
glBindTextureUnit(0, m_sprites_texture);
|
glBindTextureUnit(2, m_sprites_texture);
|
||||||
|
|
||||||
// -- setup framebuffer --
|
// -- setup framebuffer --
|
||||||
glGenFramebuffers(1, &m_framebuffer);
|
glGenFramebuffers(1, &m_framebuffer);
|
||||||
@@ -711,6 +781,18 @@ namespace glerminal
|
|||||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_screen_framebuffer_backing_texture, 0);
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_screen_framebuffer_backing_texture, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void glerminal::init_audio()
|
||||||
|
{
|
||||||
|
const ma_result result = ma_engine_init(nullptr, &m_audio_engine);
|
||||||
|
|
||||||
|
if (result != MA_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to initialize audio engine");
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_engine_set_volume(&m_audio_engine, 1);
|
||||||
|
}
|
||||||
|
|
||||||
void glerminal::deinit_glfw()
|
void glerminal::deinit_glfw()
|
||||||
{
|
{
|
||||||
glfwDestroyWindow(m_window);
|
glfwDestroyWindow(m_window);
|
||||||
@@ -730,33 +812,82 @@ namespace glerminal
|
|||||||
glDeleteBuffers(1, &m_vbo);
|
glDeleteBuffers(1, &m_vbo);
|
||||||
glDeleteBuffers(1, &m_sprites_instance_vbo);
|
glDeleteBuffers(1, &m_sprites_instance_vbo);
|
||||||
glDeleteBuffers(1, &m_offsets_instance_vbo);
|
glDeleteBuffers(1, &m_offsets_instance_vbo);
|
||||||
glDeleteBuffers(1, &m_layer_colors_buffer);
|
glDeleteBuffers(1, &m_colors_instance_vbo);
|
||||||
glDeleteBuffers(1, &m_layer_scales_buffer);
|
glDeleteBuffers(1, &m_scales_instance_vbo);
|
||||||
glDeleteProgram(m_program);
|
glDeleteProgram(m_program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void glerminal::deinit_audio()
|
||||||
|
{
|
||||||
|
for (auto& elem : m_sounds)
|
||||||
|
{
|
||||||
|
ma_sound_uninit(&elem.second);
|
||||||
|
}
|
||||||
|
ma_engine_uninit(&m_audio_engine);
|
||||||
|
}
|
||||||
|
|
||||||
void glerminal::update_sprites()
|
void glerminal::update_sprites()
|
||||||
{
|
{
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_sprites_texture);
|
glTextureSubImage2D(m_sprites_texture, 0, 0, 0, (CELL_SIZE + 2) * MAX_SPRITES_ROW, (CELL_SIZE + 2) * MAX_SPRITES_ROW, GL_RGBA, GL_UNSIGNED_BYTE, m_sprites);
|
||||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, CELL_SIZE, CELL_SIZE, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_sprites);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal::update_layer_colors()
|
void glerminal::update_colors()
|
||||||
{
|
{
|
||||||
glNamedBufferData(m_layer_colors_buffer, sizeof(m_layer_colors), m_layer_colors, GL_DYNAMIC_READ);
|
glNamedBufferSubData(m_colors_instance_vbo, 0, sizeof(m_colors), m_colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal::update_layer_scales()
|
void glerminal::update_scales()
|
||||||
{
|
{
|
||||||
glNamedBufferData(m_layer_scales_buffer, sizeof(m_layer_scales), m_layer_scales, GL_DYNAMIC_READ);
|
glNamedBufferSubData(m_scales_instance_vbo, 0, sizeof(m_scales), m_scales);
|
||||||
|
}
|
||||||
|
|
||||||
|
void glerminal::glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||||
|
{
|
||||||
|
const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window));
|
||||||
|
|
||||||
|
if (self->m_keypressed && action == GLFW_PRESS)
|
||||||
|
{
|
||||||
|
self->m_keypressed(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->m_keyreleased && action == GLFW_RELEASE)
|
||||||
|
{
|
||||||
|
self->m_keyreleased(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal_run(glerminal_init_cb init, glerminal_main_cb main)
|
void glerminal::glfw_mousemoved_handler(GLFWwindow *window, double x, double y)
|
||||||
|
{
|
||||||
|
const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window));
|
||||||
|
|
||||||
|
if (self->m_mousemoved) { self->m_mousemoved(x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void glerminal::glfw_mousepress_handler(GLFWwindow *window, int button, int action, int mods)
|
||||||
|
{
|
||||||
|
const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window));
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
glfwGetCursorPos(window, &x, &y);
|
||||||
|
|
||||||
|
if (self->m_mousepressed && action == GLFW_PRESS)
|
||||||
|
{
|
||||||
|
self->m_mousepressed(button, x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->m_mousereleased && action == GLFW_RELEASE)
|
||||||
|
{
|
||||||
|
self->m_mousereleased(button, x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void glerminal_run(glerminal_init_params params)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
glerminal::glerminal* g = new glerminal::glerminal(init, main);
|
glerminal::glerminal* g = new glerminal::glerminal(params);
|
||||||
g->run();
|
g->run();
|
||||||
delete g;
|
delete g;
|
||||||
}
|
}
|
||||||
@@ -780,39 +911,39 @@ void glerminal_flush()
|
|||||||
GLERMINAL_G->flush();
|
GLERMINAL_G->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned char sprite)
|
void glerminal_set(int x, int y, int layer, unsigned short sprite)
|
||||||
{
|
{
|
||||||
if (!GLERMINAL_G) { return; }
|
if (!GLERMINAL_G) { return; }
|
||||||
|
|
||||||
GLERMINAL_G->set(x, y, layer, sprite);
|
GLERMINAL_G->set(x + 1, y + 1, layer, sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned char layer)
|
unsigned short glerminal_get(int x, int y, int layer)
|
||||||
{
|
{
|
||||||
if (!GLERMINAL_G) { return 0; }
|
if (!GLERMINAL_G) { return 0; }
|
||||||
|
|
||||||
return GLERMINAL_G->get(x, y, layer);
|
return GLERMINAL_G->get(x + 1, y + 1, layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset)
|
void glerminal_offset(int x, int y, int layer, float x_offset, float y_offset)
|
||||||
{
|
{
|
||||||
if (!GLERMINAL_G) { return; }
|
if (!GLERMINAL_G) { return; }
|
||||||
|
|
||||||
GLERMINAL_G->offset(x, y, layer, x_offset, y_offset);
|
GLERMINAL_G->offset(x + 1, y + 1, layer, x_offset, y_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal_layer_color(unsigned char layer, unsigned int color)
|
void glerminal_color(int x, int y, int layer, unsigned int color)
|
||||||
{
|
{
|
||||||
if (!GLERMINAL_G) { return; }
|
if (!GLERMINAL_G) { return; }
|
||||||
|
|
||||||
GLERMINAL_G->layer_color(layer, color);
|
GLERMINAL_G->color(x + 1, y + 1, layer, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal_layer_scale(unsigned char layer, float scale)
|
void glerminal_scale(int x, int y, int layer, float scale)
|
||||||
{
|
{
|
||||||
if (!GLERMINAL_G) { return; }
|
if (!GLERMINAL_G) { return; }
|
||||||
|
|
||||||
GLERMINAL_G->layer_scale(layer, scale);
|
GLERMINAL_G->scale(x + 1, y + 1, layer, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
int glerminal_load_sprites_file(const char* filename)
|
int glerminal_load_sprites_file(const char* filename)
|
||||||
@@ -853,3 +984,10 @@ int glerminal_load_sprites_buffer(unsigned char width, unsigned char height, con
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void glerminal_sound(const char* name)
|
||||||
|
{
|
||||||
|
if (!GLERMINAL_G) { return; }
|
||||||
|
|
||||||
|
GLERMINAL_G->play_sound(name);
|
||||||
|
}
|
||||||
|
7
source/miniaudio.c
Normal file
7
source/miniaudio.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef GLERMINAL_MINIAUDIO_H
|
||||||
|
#define GLERMINAL_MINIAUDIO_H
|
||||||
|
|
||||||
|
#define MINIAUDIO_IMPLEMENTATION
|
||||||
|
#include "miniaudio.h"
|
||||||
|
|
||||||
|
#endif//GLERMINAL_MINIAUDIO_H
|
92621
source/miniaudio.h
Normal file
92621
source/miniaudio.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -25,12 +25,12 @@ namespace
|
|||||||
glerminal_quit();
|
glerminal_quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainloop(float) {}
|
void mainloop(double) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
glerminal_run(init, mainloop);
|
glerminal_run({init, mainloop});
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
unsigned char pixels[(GRID_WIDTH * CELL_SCALE * 8) * (GRID_HEIGHT * CELL_SCALE * 8) * 3];
|
unsigned char pixels[(GRID_WIDTH * CELL_SIZE * CELL_SCALE) * (GRID_HEIGHT * CELL_SIZE * CELL_SCALE) * 3];
|
||||||
}
|
}
|
||||||
|
|
||||||
void glerminal_test_save_image()
|
void glerminal_test_save_image()
|
||||||
@@ -21,5 +21,5 @@ void glerminal_test_save_image()
|
|||||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
|
||||||
stbi_flip_vertically_on_write(true);
|
stbi_flip_vertically_on_write(true);
|
||||||
stbi_write_png("image.png", GRID_WIDTH * CELL_SCALE * 8, GRID_HEIGHT * CELL_SCALE * 8, 3, pixels, GRID_WIDTH * CELL_SCALE * 8 * 3);
|
stbi_write_png("image.png", GRID_WIDTH * CELL_SIZE * CELL_SCALE, GRID_HEIGHT * CELL_SIZE * CELL_SCALE, 3, pixels, GRID_WIDTH * CELL_SIZE * CELL_SCALE * 3);
|
||||||
}
|
}
|
Reference in New Issue
Block a user