mirror of
https://git.shylie.info/shylie/glerminal.git
synced 2025-10-27 23:30:08 +00:00
Compare commits
20 Commits
139681a3fd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fb3eeb6ec9 | |||
| 263cf68ca2 | |||
| b8e616c8d6 | |||
| 1bfbab7a96 | |||
| d156005441 | |||
| 82389b8c12 | |||
| 0a9d211942 | |||
| 937693ce6a | |||
| 365cad551b | |||
| 5fbeb1e4e9 | |||
| 11ffc40bbb | |||
| db46885ee9 | |||
| 20fad92e4f | |||
| 7c0c02b9af | |||
| 1a1f4e8b13 | |||
|
|
6663804c88 | ||
|
|
9d88ebbb3b | ||
|
|
76bfd67f4e | ||
|
|
4811e4d970 | ||
|
|
e402b5f5a3 |
@@ -5,7 +5,7 @@ on: push
|
||||
|
||||
jobs:
|
||||
build-app:
|
||||
runs-on: linux_amd64
|
||||
runs-on: shy-server
|
||||
steps:
|
||||
- name: Checkout current
|
||||
uses: actions/checkout@v4
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
lfs: true
|
||||
- run: cd prev && git checkout 10a90a5f6a
|
||||
- run: cd prev && git checkout 263cf68ca2
|
||||
- name: Build current
|
||||
run: cmake -S curr -B curr/build -DGLERMINAL_TEST=ON && cmake --build curr/build
|
||||
- name: Build previous
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
build/
|
||||
cmake-build-*/
|
||||
.idea/
|
||||
.idea/
|
||||
.cache/
|
||||
|
||||
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "glfw"]
|
||||
path = glfw
|
||||
url = https://git.shylie.info/shylie/glfw.git
|
||||
[submodule "Lua"]
|
||||
path = Lua
|
||||
url = https://git.shylie.info/shylie/Lua.git
|
||||
url = https://github.com/glfw/glfw.git
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.28)
|
||||
|
||||
project(glerminal
|
||||
VERSION 0.1.0
|
||||
LANGUAGES C CXX
|
||||
VERSION 0.1.0
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
option(GLERMINAL_OPENGL_DEBUG_CONTEXT "" OFF)
|
||||
@@ -11,72 +11,58 @@ set(GLERMINAL_GRID_WIDTH 40 CACHE STRING "")
|
||||
set(GLERMINAL_GRID_HEIGHT 25 CACHE STRING "")
|
||||
set(GLERMINAL_LAYER_COUNT 64 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)
|
||||
|
||||
add_subdirectory(glfw)
|
||||
add_subdirectory(Lua)
|
||||
|
||||
add_library(glerminallib STATIC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/glerminal-config.h
|
||||
include/glerminal.h
|
||||
add_library(glerminal STATIC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/glerminal-config.h
|
||||
include/glerminal.h
|
||||
|
||||
source/stb_image.h
|
||||
source/glerminal-private.h
|
||||
source/glerminal.cpp
|
||||
source/stb_image.h
|
||||
source/glerminal-private.h
|
||||
source/glerminal.cpp
|
||||
|
||||
source/glad/glad.h
|
||||
source/KHR/khrplatform.h
|
||||
source/glad.c
|
||||
source/glad/glad.h
|
||||
source/KHR/khrplatform.h
|
||||
source/glad.c
|
||||
|
||||
source/miniaudio.h
|
||||
source/miniaudio.c
|
||||
)
|
||||
|
||||
set_target_properties(glerminallib
|
||||
PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
set_target_properties(glerminal
|
||||
PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
)
|
||||
|
||||
target_include_directories(glerminallib
|
||||
PUBLIC
|
||||
include
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
PRIVATE
|
||||
source
|
||||
)
|
||||
|
||||
target_link_libraries(glerminallib
|
||||
PUBLIC
|
||||
glfw
|
||||
)
|
||||
|
||||
target_compile_definitions(glerminallib
|
||||
PUBLIC
|
||||
GLERMINAL_VERSION=${PROJECT_VERSION}
|
||||
GLERMINAL_VERSION_MAJOR=${PROJECT_VERSION_MAJOR}
|
||||
GLERMINAL_VERSION_MINOR=${PROJECT_VERSION_MINOR}
|
||||
GLERMINAL_VERSION_PATCH=${PROJECT_VERSION_PATCH}
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
target_link_options(glerminallib
|
||||
PUBLIC
|
||||
"/ENTRY:mainCRTStartup"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(glerminal WIN32
|
||||
source/glerminal-main.cpp
|
||||
target_include_directories(glerminal
|
||||
PUBLIC
|
||||
include
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
PRIVATE
|
||||
source
|
||||
)
|
||||
|
||||
target_link_libraries(glerminal
|
||||
PRIVATE
|
||||
glerminallib
|
||||
lua_static
|
||||
PUBLIC
|
||||
glfw
|
||||
)
|
||||
|
||||
if (PROJECT_IS_TOP_LEVEL)
|
||||
add_subdirectory(examples examples)
|
||||
target_compile_definitions(glerminal
|
||||
PUBLIC
|
||||
GLERMINAL_VERSION=${PROJECT_VERSION}
|
||||
GLERMINAL_VERSION_MAJOR=${PROJECT_VERSION_MAJOR}
|
||||
GLERMINAL_VERSION_MINOR=${PROJECT_VERSION_MINOR}
|
||||
GLERMINAL_VERSION_PATCH=${PROJECT_VERSION_PATCH}
|
||||
)
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
add_subdirectory(examples examples)
|
||||
endif()
|
||||
|
||||
if (GLERMINAL_TEST)
|
||||
add_subdirectory(tests tests)
|
||||
endif()
|
||||
if(GLERMINAL_TEST)
|
||||
add_subdirectory(tests tests)
|
||||
endif()
|
||||
|
||||
1
Lua
1
Lua
Submodule Lua deleted from 88246d621a
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 |
@@ -36,5 +36,5 @@ list(TRANSFORM EXAMPLE_RESOURCES PREPEND ${CMAKE_CURRENT_BINARY_DIR}/)
|
||||
foreach(SOURCE_FILE ${EXAMPLE_SOURCES})
|
||||
get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE)
|
||||
add_executable(${SOURCE_FILENAME} WIN32 ${SOURCE_FILE} ${EXAMPLE_RESOURCES})
|
||||
target_link_libraries(${SOURCE_FILENAME} PRIVATE glerminallib)
|
||||
endforeach()
|
||||
target_link_libraries(${SOURCE_FILENAME} PRIVATE glerminal)
|
||||
endforeach()
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace
|
||||
{
|
||||
for (int k = 0; k < LAYER_COUNT; k++)
|
||||
{
|
||||
glerminal_set(i, j, k, rand() % 4);
|
||||
glerminal_offset(i, j, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32);
|
||||
glerminal_set(i + 1, j + 1, k, rand() % 4);
|
||||
glerminal_offset(i + 1, j + 1, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -25,9 +25,9 @@ namespace
|
||||
time += dt;
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -18,16 +18,16 @@ namespace
|
||||
{
|
||||
glerminal_load_sprites_file("resources/rogue.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++)
|
||||
{
|
||||
for (int k = 0; k < WALL_LAYERS; k++)
|
||||
{
|
||||
const unsigned char v = (k + 1) * (256 / WALL_LAYERS) - 1;
|
||||
const unsigned int c = (0xFF << 24) | (v << 16) | (v << 8) | v;
|
||||
|
||||
if (i == 0 || j == 0 || i == GRID_WIDTH - 1 || j == GRID_HEIGHT - 1)
|
||||
if (i == 1 || j == 1 || i == GRID_WIDTH || j == GRID_HEIGHT)
|
||||
{
|
||||
glerminal_set(i, j, k, floor);
|
||||
}
|
||||
@@ -48,12 +48,12 @@ namespace
|
||||
static double time = 0;
|
||||
time += dt;
|
||||
|
||||
const float cx = GRID_WIDTH / 2.0f * cosf(time / 2) + GRID_WIDTH / 2.0f;
|
||||
const float cy = GRID_HEIGHT / 2.0f * sinf(time / 2) + GRID_HEIGHT / 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 + 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++)
|
||||
{
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace
|
||||
glerminal_load_sprites_file("resources/towers.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++)
|
||||
{
|
||||
const int c = rand() % (LAYER_COUNT * 3 / 4) + LAYER_COUNT / 4;
|
||||
for (int k = 0; k < c; k++)
|
||||
@@ -40,12 +40,12 @@ namespace
|
||||
|
||||
time += dt;
|
||||
|
||||
const float cx = (GRID_WIDTH / 2.0f) * cosf(time / 3.1415f) + (GRID_WIDTH / 2.0f);
|
||||
const float cy = (GRID_HEIGHT / 2.0f) * sinf(time / 3.1415f) + (GRID_HEIGHT / 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) + 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++)
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ void glerminal_flush();
|
||||
* @param layer layer of the cell in the range [0, LAYER_COUNT)
|
||||
* @param sprite sprite's index in the range [0, 4096)
|
||||
*/
|
||||
void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite);
|
||||
void glerminal_set(int x, int y, int layer, unsigned short sprite);
|
||||
/**
|
||||
* @brief Get a cell's sprite
|
||||
* @param x position of the cell in the range [0, GRID_WIDTH)
|
||||
@@ -50,7 +50,7 @@ void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsign
|
||||
* @param layer layer of the cell in the range [0, LAYER_COUNT)
|
||||
* @return sprite index currently assigned to the cell
|
||||
*/
|
||||
unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned short layer);
|
||||
unsigned short glerminal_get(int x, int y, int layer);
|
||||
/**
|
||||
* @brief Set a cell's offset
|
||||
* @param x position of the cell in the range [0, GRID_WIDTH)
|
||||
@@ -59,7 +59,7 @@ unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned short lay
|
||||
* @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 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 cell's color
|
||||
@@ -68,7 +68,7 @@ void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, flo
|
||||
* @param layer layer of the cell in the range [0, LAYER_COUNT)
|
||||
* @param color The new color
|
||||
*/
|
||||
void glerminal_color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color);
|
||||
void glerminal_color(int x, int y, int layer, unsigned int color);
|
||||
/**
|
||||
* @brief Set a cell's scale
|
||||
* @param x position of the cell in the range [0, GRID_WIDTH)
|
||||
@@ -76,7 +76,7 @@ void glerminal_color(unsigned char x, unsigned char y, unsigned char layer, unsi
|
||||
* @param layer layer of the cell in the range [0, LAYER_COUNT)
|
||||
* @param scale The new scale
|
||||
*/
|
||||
void glerminal_scale(unsigned char x, unsigned char y, unsigned char layer, float scale);
|
||||
void glerminal_scale(int x, int y, int layer, float scale);
|
||||
|
||||
/**
|
||||
* @brief Load sprites from a png file
|
||||
@@ -92,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);
|
||||
|
||||
void glerminal_sound(const char* name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
local time = 0
|
||||
|
||||
function glerminal.init()
|
||||
if not glerminal.sprites('sprites.png') then
|
||||
print('failed to load sprites')
|
||||
end
|
||||
|
||||
for i = 1, 40 do
|
||||
for j = 1, 25 do
|
||||
glerminal.set(i, j, 1, 2)
|
||||
end
|
||||
end
|
||||
|
||||
glerminal.tint(1, 0xA0FFFFFF)
|
||||
|
||||
glerminal.flush()
|
||||
end
|
||||
|
||||
function glerminal.main(dt)
|
||||
time = time + dt / 2
|
||||
|
||||
for i = 1, 40 do
|
||||
for j = 1, 25 do
|
||||
glerminal.offset(i, j, 1, math.cos(time * i / math.pi), math.sin(time * j / math.pi))
|
||||
end
|
||||
end
|
||||
|
||||
glerminal.flush()
|
||||
end
|
||||
|
||||
function glerminal.keypresse(key) end
|
||||
function glerminal.keyrelease(key) end
|
||||
function glerminal.mousemove(x, y) end
|
||||
function glerminal.mousepress(button, x, y) end
|
||||
function glerminal.mouserelease(button, x, y) end
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6dee3efcdfa72e54a602f69643907bb8e8a3328d2b40c2116dce22ff179d8892
|
||||
size 182
|
||||
@@ -16,7 +16,8 @@ enum
|
||||
GRID_WIDTH = @GLERMINAL_GRID_WIDTH@,
|
||||
GRID_HEIGHT = @GLERMINAL_GRID_HEIGHT@,
|
||||
LAYER_COUNT = @GLERMINAL_LAYER_COUNT@,
|
||||
CELL_SCALE = @GLERMINAL_CELL_SCALE@
|
||||
CELL_SCALE = @GLERMINAL_CELL_SCALE@,
|
||||
CELL_SIZE = @GLERMINAL_CELL_SIZE@
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,340 +0,0 @@
|
||||
#include <glerminal.h>
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WINDOWS_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#define CHANGE_WORKING_DIRECTORY(path) !(SetCurrentDirectory(path))
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#define CHANGE_WORKING_DIRECTORY(path) chdir(path)
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
int lglerminal_quit(lua_State* L)
|
||||
{
|
||||
glerminal_quit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lglerminal_flush(lua_State* L)
|
||||
{
|
||||
glerminal_flush();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lglerminal_set(lua_State* L)
|
||||
{
|
||||
const unsigned char x = luaL_checkinteger(L, 1) - 1;
|
||||
const unsigned char y = luaL_checkinteger(L, 2) - 1;
|
||||
const unsigned char layer = luaL_checkinteger(L, 3) - 1;
|
||||
const unsigned short sprite = luaL_checkinteger(L, 4) - 1;
|
||||
glerminal_set(x, y, layer, sprite);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lglerminal_get(lua_State* L)
|
||||
{
|
||||
const unsigned char x = luaL_checkinteger(L, 1) - 1;
|
||||
const unsigned char y = luaL_checkinteger(L, 2) - 1;
|
||||
const unsigned char layer = luaL_checkinteger(L, 3) - 1;
|
||||
lua_pushnumber(L, glerminal_get(x, y, layer) + 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lglerminal_offset(lua_State* L)
|
||||
{
|
||||
const unsigned char x = luaL_checkinteger(L, 1) - 1;
|
||||
const unsigned char y = luaL_checkinteger(L, 2) - 1;
|
||||
const unsigned char layer = luaL_checkinteger(L, 3) - 1;
|
||||
const float ox = luaL_checknumber(L, 4);
|
||||
const float oy = luaL_checknumber(L, 5);
|
||||
glerminal_offset(x, y, layer, ox, oy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lglerminal_layer_color(lua_State* L)
|
||||
{
|
||||
const unsigned char x = luaL_checkinteger(L, 1) - 1;
|
||||
const unsigned char y = luaL_checkinteger(L, 2) - 1;
|
||||
const unsigned char layer = luaL_checkinteger(L, 3) - 1;
|
||||
const unsigned int color = luaL_checkinteger(L, 4);
|
||||
glerminal_color(x, y, layer, color);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lglerminal_layer_scale(lua_State* L)
|
||||
{
|
||||
const unsigned char x = luaL_checkinteger(L, 1) - 1;
|
||||
const unsigned char y = luaL_checkinteger(L, 2) - 1;
|
||||
const unsigned char layer = luaL_checkinteger(L, 3) - 1;
|
||||
const float scale = luaL_checknumber(L, 4);
|
||||
glerminal_scale(x, y, layer, scale);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lglerminal_load_sprites_file(lua_State* L)
|
||||
{
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
lua_pushboolean(L, glerminal_load_sprites_file(path));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg lglerminal_methods[] =
|
||||
{
|
||||
{ "quit", lglerminal_quit },
|
||||
{ "flush", lglerminal_flush },
|
||||
{ "set", lglerminal_set },
|
||||
{ "get", lglerminal_get },
|
||||
{ "offset", lglerminal_offset },
|
||||
{ "tint", lglerminal_layer_color },
|
||||
{ "scale", lglerminal_layer_scale },
|
||||
{ "sprites", lglerminal_load_sprites_file },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
int message_handler(lua_State* L)
|
||||
{
|
||||
luaL_traceback(L, L, lua_tostring(L, -1), 1);
|
||||
lua_remove(L, -2);
|
||||
|
||||
glerminal_quit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
lua_State* L;
|
||||
|
||||
void init()
|
||||
{
|
||||
lua_pushcfunction(L, message_handler);
|
||||
const int handler = lua_gettop(L);
|
||||
lua_getglobal(L, "glerminal");
|
||||
lua_getfield(L, -1, "init");
|
||||
lua_remove(L, -2);
|
||||
if (lua_pcall(L, 0, 0, handler) != LUA_OK)
|
||||
{
|
||||
std::cout << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_remove(L, handler);
|
||||
}
|
||||
|
||||
void mainloop(double dt)
|
||||
{
|
||||
lua_pushcfunction(L, message_handler);
|
||||
const int handler = lua_gettop(L);
|
||||
lua_getglobal(L, "glerminal");
|
||||
lua_getfield(L, -1, "main");
|
||||
lua_remove(L, -2);
|
||||
lua_pushnumber(L, dt);
|
||||
if (lua_pcall(L, 1, 0, handler) != LUA_OK)
|
||||
{
|
||||
std::cout << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_remove(L, handler);
|
||||
}
|
||||
|
||||
void keypressed(int key)
|
||||
{
|
||||
const char* const name = glfwGetKeyName(key, 0);
|
||||
if (name)
|
||||
{
|
||||
lua_pushcfunction(L, message_handler);
|
||||
const int handler = lua_gettop(L);
|
||||
lua_getglobal(L, "glerminal");
|
||||
lua_getfield(L, -1, "keypress");
|
||||
lua_remove(L, -2);
|
||||
lua_pushstring(L, name);
|
||||
if (lua_pcall(L, 1, 0, handler) != LUA_OK)
|
||||
{
|
||||
std::cout << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_remove(L, handler);
|
||||
}
|
||||
}
|
||||
|
||||
void keyrelease(int key)
|
||||
{
|
||||
const char* const name = glfwGetKeyName(key, 0);
|
||||
if (name)
|
||||
{
|
||||
lua_pushcfunction(L, message_handler);
|
||||
const int handler = lua_gettop(L);
|
||||
lua_getglobal(L, "glerminal");
|
||||
lua_getfield(L, -1, "keyrelease");
|
||||
lua_remove(L, -2);
|
||||
lua_pushstring(L, name);
|
||||
if (lua_pcall(L, 1, 0, handler) != LUA_OK)
|
||||
{
|
||||
std::cout << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_remove(L, handler);
|
||||
}
|
||||
}
|
||||
|
||||
void mousemove(double x, double y)
|
||||
{
|
||||
lua_pushcfunction(L, message_handler);
|
||||
const int handler = lua_gettop(L);
|
||||
lua_getglobal(L, "glerminal");
|
||||
lua_getfield(L, -1, "mousemove");
|
||||
lua_remove(L, -2);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
if (lua_pcall(L, 2, 0, handler) != LUA_OK)
|
||||
{
|
||||
std::cout << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_remove(L, handler);
|
||||
}
|
||||
|
||||
void mousepress(int button, double x, double y)
|
||||
{
|
||||
const char* button_name = nullptr;
|
||||
switch (button)
|
||||
{
|
||||
case GLFW_MOUSE_BUTTON_LEFT:
|
||||
button_name = "left";
|
||||
break;
|
||||
|
||||
case GLFW_MOUSE_BUTTON_RIGHT:
|
||||
button_name = "right";
|
||||
break;
|
||||
|
||||
case GLFW_MOUSE_BUTTON_MIDDLE:
|
||||
button_name = "middle";
|
||||
break;
|
||||
}
|
||||
|
||||
if (button_name)
|
||||
{
|
||||
lua_pushcfunction(L, message_handler);
|
||||
const int handler = lua_gettop(L);
|
||||
lua_getglobal(L, "glerminal");
|
||||
lua_getfield(L, -1, "mousepress");
|
||||
lua_remove(L, -2);
|
||||
lua_pushstring(L, button_name);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
if (lua_pcall(L, 3, 0, handler) != LUA_OK)
|
||||
{
|
||||
std::cout << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_remove(L, handler);
|
||||
}
|
||||
}
|
||||
|
||||
void mouserelease(int button, double x, double y)
|
||||
{
|
||||
const char* button_name = nullptr;
|
||||
switch (button)
|
||||
{
|
||||
case GLFW_MOUSE_BUTTON_LEFT:
|
||||
button_name = "left";
|
||||
break;
|
||||
|
||||
case GLFW_MOUSE_BUTTON_RIGHT:
|
||||
button_name = "right";
|
||||
break;
|
||||
|
||||
case GLFW_MOUSE_BUTTON_MIDDLE:
|
||||
button_name = "middle";
|
||||
break;
|
||||
}
|
||||
|
||||
if (button_name)
|
||||
{
|
||||
lua_pushcfunction(L, message_handler);
|
||||
const int handler = lua_gettop(L);
|
||||
lua_getglobal(L, "glerminal");
|
||||
lua_getfield(L, -1, "mouserelease");
|
||||
lua_remove(L, -2);
|
||||
lua_pushstring(L, button_name);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
if (lua_pcall(L, 3, 0, handler) != LUA_OK)
|
||||
{
|
||||
std::cout << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_remove(L, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
std::cout << "Usage: " << argv[0] << " <project directory>" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (CHANGE_WORKING_DIRECTORY(argv[1]))
|
||||
{
|
||||
std::cout << "Failed to find project directory" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
|
||||
luaL_newlib(L, lglerminal_methods);
|
||||
lua_setglobal(L, "glerminal");
|
||||
|
||||
lua_pushcfunction(L, message_handler);
|
||||
const int handler = lua_gettop(L);
|
||||
if (luaL_loadfile(L, "main.lua") != LUA_OK)
|
||||
{
|
||||
const char* str = lua_tostring(L, -1);
|
||||
std::cout << str << std::endl;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
else if (lua_pcall(L, 0, LUA_MULTRET, handler) != LUA_OK)
|
||||
{
|
||||
const char* str = lua_tostring(L, -1);
|
||||
std::cout << str << std::endl;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
glerminal_init_params params;
|
||||
params.init = init;
|
||||
params.main = mainloop;
|
||||
params.keypress = keypressed;
|
||||
params.keyrelease = keyrelease;
|
||||
params.moved = mousemove;
|
||||
params.mousepress = mousepress;
|
||||
params.mouserelease = mouserelease;
|
||||
glerminal_run(params);
|
||||
}
|
||||
|
||||
lua_close(L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2,27 +2,31 @@
|
||||
#define GLERMINAL_PRIVATE_H
|
||||
|
||||
#include "glerminal.h"
|
||||
#include "miniaudio.h"
|
||||
|
||||
#include <stb_image.h>
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
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_HEIGHT = ::GRID_HEIGHT;
|
||||
constexpr unsigned int LAYER_COUNT = ::LAYER_COUNT;
|
||||
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 SCREEN_WIDTH = GRID_WIDTH * 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
|
||||
{
|
||||
@@ -41,12 +45,14 @@ namespace glerminal
|
||||
|
||||
void flush();
|
||||
|
||||
void set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite);
|
||||
unsigned short get(unsigned char x, unsigned char y, unsigned char layer) const;
|
||||
void offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset);
|
||||
void color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color);
|
||||
void scale(unsigned char x, unsigned char y, unsigned char layer, float scale);
|
||||
void set(int x, int y, int layer, unsigned short sprite);
|
||||
unsigned short get(int x, int y, int layer) const;
|
||||
void offset(int x, int y, int layer, float x_offset, float y_offset);
|
||||
void color(int x, int y, int layer, unsigned int color);
|
||||
void scale(int x,int y, int layer, float scale);
|
||||
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:
|
||||
// glfw data
|
||||
@@ -69,15 +75,13 @@ namespace glerminal
|
||||
unsigned int m_screen_framebuffer_backing_texture;
|
||||
unsigned int m_colors_instance_vbo;
|
||||
unsigned int m_scales_instance_vbo;
|
||||
unsigned int m_screen_size_uniform_location;
|
||||
unsigned int m_palette_uniform_location;
|
||||
|
||||
// per-cell data
|
||||
|
||||
unsigned short m_cells[GRID_AREA * LAYER_COUNT];
|
||||
float m_offsets[GRID_AREA * LAYER_COUNT * 2];
|
||||
unsigned char m_colors[GRID_AREA * LAYER_COUNT * 4];
|
||||
float m_scales[GRID_AREA * LAYER_COUNT];
|
||||
unsigned short m_cells[GRID_AREA_2 * LAYER_COUNT];
|
||||
float m_offsets[GRID_AREA_2 * LAYER_COUNT * 2];
|
||||
unsigned char m_colors[GRID_AREA_2 * LAYER_COUNT * 4];
|
||||
float m_scales[GRID_AREA_2 * LAYER_COUNT];
|
||||
|
||||
// library state
|
||||
|
||||
@@ -87,6 +91,9 @@ namespace glerminal
|
||||
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
|
||||
mutable std::ofstream m_log;
|
||||
#endif
|
||||
@@ -95,9 +102,13 @@ namespace glerminal
|
||||
void init_glfw();
|
||||
void init_gl();
|
||||
|
||||
void init_audio();
|
||||
|
||||
void deinit_glfw();
|
||||
void deinit_gl();
|
||||
|
||||
void deinit_audio();
|
||||
|
||||
void update_sprites();
|
||||
void update_colors();
|
||||
void update_scales();
|
||||
@@ -108,4 +119,4 @@ namespace glerminal
|
||||
};
|
||||
}
|
||||
|
||||
#endif//GLERMINAL_PRIVATE_H
|
||||
#endif//GLERMINAL_PRIVATE_H
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_ONLY_PNG
|
||||
#define STBI_MAX_DIMENSIONS 512
|
||||
#define STBI_MAX_DIMENSIONS 2048
|
||||
#include "glerminal-private.h"
|
||||
|
||||
#define GRID_SIZE_UNIFORM_NAME "grid_size"
|
||||
@@ -8,6 +8,7 @@
|
||||
#define LAYERS_UNIFORM_NAME "layers"
|
||||
#define LAYER_COUNT_UNIFORM_NAME "layer_count"
|
||||
#define ATLAS_WIDTH_UNIFORM_NAME "atlas_width"
|
||||
#define CELL_SIZE_UNIFORM_NAME "cell_size"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -33,6 +34,7 @@ namespace
|
||||
"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 int " ATLAS_WIDTH_UNIFORM_NAME ";\n"
|
||||
"out VS_OUT {\n"
|
||||
@@ -48,9 +50,9 @@ namespace
|
||||
" vs_out.sprite = sprite;\n"
|
||||
" vs_out.layer = layer;\n"
|
||||
" vs_out.layer_color = color;\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 / 16, (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16);\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 ".z), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z));\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"
|
||||
" 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(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"
|
||||
"}";
|
||||
|
||||
@@ -64,6 +66,7 @@ namespace
|
||||
"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 int " ATLAS_WIDTH_UNIFORM_NAME ";\n"
|
||||
"out VS_OUT {\n"
|
||||
@@ -77,10 +80,10 @@ namespace
|
||||
" gl_Layer = layer;\n"
|
||||
" vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n"
|
||||
" vs_out.sprite = sprite;\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 / 16, (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16);\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"
|
||||
" vs_out.layer_color = color;\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 ".z), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z));\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"
|
||||
" 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"
|
||||
"}";
|
||||
|
||||
@@ -221,7 +224,7 @@ namespace glerminal
|
||||
throw std::runtime_error("No main callback provided.");
|
||||
}
|
||||
|
||||
for (int i = 0; i < GRID_AREA * LAYER_COUNT; i++)
|
||||
for (int i = 0; i < GRID_AREA_2 * LAYER_COUNT; i++)
|
||||
{
|
||||
m_colors[i * 4 + 0] = m_colors[i * 4 + 1] = m_colors[i * 4 + 2] = m_colors[i * 4 + 3] = 255;
|
||||
m_scales[i] = 1;
|
||||
@@ -229,6 +232,7 @@ namespace glerminal
|
||||
|
||||
init_glfw();
|
||||
init_gl();
|
||||
init_audio();
|
||||
|
||||
GLERMINAL_G = this;
|
||||
|
||||
@@ -237,6 +241,7 @@ namespace glerminal
|
||||
|
||||
glerminal::~glerminal()
|
||||
{
|
||||
deinit_audio();
|
||||
deinit_gl();
|
||||
deinit_glfw();
|
||||
|
||||
@@ -275,7 +280,7 @@ namespace glerminal
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
|
||||
glBindVertexArray(m_vao);
|
||||
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);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_screen_framebuffer);
|
||||
@@ -283,28 +288,25 @@ namespace glerminal
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
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);
|
||||
|
||||
glfwSwapInterval(0);
|
||||
glfwSwapBuffers(m_window);
|
||||
glBlitNamedFramebuffer(m_screen_framebuffer, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glfwSwapInterval(1);
|
||||
glfwSwapBuffers(m_window);
|
||||
}
|
||||
|
||||
void glerminal::set(unsigned char x, unsigned char y, unsigned char layer, unsigned short 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 short 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
|
||||
{
|
||||
@@ -312,26 +314,32 @@ 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 + layer * GRID_AREA) + 1] = y_offset;
|
||||
m_offsets[2 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 0] = x_offset;
|
||||
m_offsets[2 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 1] = y_offset;
|
||||
}
|
||||
}
|
||||
|
||||
void glerminal::color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color)
|
||||
void glerminal::color(int x, int y, int layer, unsigned int color)
|
||||
{
|
||||
m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 0] = ((color >> 0) & 0xFF);
|
||||
m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 1] = ((color >> 8) & 0xFF);
|
||||
m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 2] = ((color >> 16) & 0xFF);
|
||||
m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 3] = ((color >> 24) & 0xFF);
|
||||
if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT)
|
||||
{
|
||||
m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 0] = (color >> 0) & 0xFF;
|
||||
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::scale(unsigned char x, unsigned char y, unsigned char layer, float scale)
|
||||
void glerminal::scale(int x, int y, int layer, float scale)
|
||||
{
|
||||
m_scales[x + y * GRID_WIDTH + layer * GRID_AREA] = 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)
|
||||
@@ -360,6 +368,39 @@ namespace glerminal
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
glfwInit();
|
||||
@@ -615,10 +656,9 @@ namespace glerminal
|
||||
}
|
||||
|
||||
// setup uniforms
|
||||
m_screen_size_uniform_location = glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME);
|
||||
|
||||
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
|
||||
@@ -699,7 +739,6 @@ namespace glerminal
|
||||
update_sprites();
|
||||
|
||||
glBindTextureUnit(2, m_sprites_texture);
|
||||
const auto err = glGetError();
|
||||
|
||||
// -- setup framebuffer --
|
||||
glGenFramebuffers(1, &m_framebuffer);
|
||||
@@ -742,6 +781,18 @@ namespace glerminal
|
||||
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()
|
||||
{
|
||||
glfwDestroyWindow(m_window);
|
||||
@@ -766,6 +817,15 @@ namespace glerminal
|
||||
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()
|
||||
{
|
||||
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);
|
||||
@@ -783,7 +843,7 @@ namespace glerminal
|
||||
|
||||
void glerminal::glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window));
|
||||
const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window));
|
||||
|
||||
if (self->m_keypressed && action == GLFW_PRESS)
|
||||
{
|
||||
@@ -798,26 +858,26 @@ namespace glerminal
|
||||
|
||||
void glerminal::glfw_mousemoved_handler(GLFWwindow *window, double x, double y)
|
||||
{
|
||||
glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window));
|
||||
const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window));
|
||||
|
||||
if (self->m_mousemoved) { self->m_mousemoved(x / CELL_SIZE, y / CELL_SIZE); }
|
||||
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)
|
||||
{
|
||||
glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window));
|
||||
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, y / CELL_SIZE);
|
||||
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, y / CELL_SIZE);
|
||||
self->m_mousereleased(button, x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -851,39 +911,39 @@ void glerminal_flush()
|
||||
GLERMINAL_G->flush();
|
||||
}
|
||||
|
||||
void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite)
|
||||
void glerminal_set(int x, int y, int layer, unsigned short sprite)
|
||||
{
|
||||
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 short layer)
|
||||
unsigned short glerminal_get(int x, int y, int layer)
|
||||
{
|
||||
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; }
|
||||
|
||||
GLERMINAL_G->offset(x, y, layer, x_offset, y_offset);
|
||||
GLERMINAL_G->offset(x + 1, y + 1, layer, x_offset, y_offset);
|
||||
}
|
||||
|
||||
void glerminal_color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color)
|
||||
void glerminal_color(int x, int y, int layer, unsigned int color)
|
||||
{
|
||||
if (!GLERMINAL_G) { return; }
|
||||
|
||||
GLERMINAL_G->color(x, y, layer, color);
|
||||
GLERMINAL_G->color(x + 1, y + 1, layer, color);
|
||||
}
|
||||
|
||||
void glerminal_scale(unsigned char x, unsigned char y, unsigned char layer, float scale)
|
||||
void glerminal_scale(int x, int y, int layer, float scale)
|
||||
{
|
||||
if (!GLERMINAL_G) { return; }
|
||||
|
||||
GLERMINAL_G->scale(x, y, layer, scale);
|
||||
GLERMINAL_G->scale(x + 1, y + 1, layer, scale);
|
||||
}
|
||||
|
||||
int glerminal_load_sprites_file(const char* filename)
|
||||
@@ -896,7 +956,7 @@ int glerminal_load_sprites_file(const char* filename)
|
||||
stbi_uc* const buffer = stbi_load(filename, &w, &h, nullptr, 4);
|
||||
|
||||
// verify atlas size is a multiple of CELL_SIZE in each dimension
|
||||
if (w % glerminal::CELL_SIZE == 0 && h % glerminal::CELL_SIZE == 0)
|
||||
if (buffer && w % glerminal::CELL_SIZE == 0 && h % glerminal::CELL_SIZE == 0)
|
||||
{
|
||||
GLERMINAL_G->load_atlas(w / glerminal::CELL_SIZE, h / glerminal::CELL_SIZE, reinterpret_cast<unsigned int*>(buffer));
|
||||
|
||||
@@ -923,4 +983,11 @@ int glerminal_load_sprites_buffer(unsigned char width, unsigned char height, con
|
||||
{
|
||||
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
@@ -17,7 +17,7 @@ target_include_directories(test-common
|
||||
${CMAKE_SOURCE_DIR}/source
|
||||
)
|
||||
|
||||
target_link_libraries(test-common PRIVATE glerminallib)
|
||||
target_link_libraries(test-common PRIVATE glerminal)
|
||||
|
||||
file(GLOB_RECURSE
|
||||
TEST_RESOURCES
|
||||
@@ -52,5 +52,5 @@ list(TRANSFORM TEST_RESOURCES PREPEND ${CMAKE_CURRENT_BINARY_DIR}/)
|
||||
foreach(SOURCE_FILE ${TEST_SOURCES})
|
||||
get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE)
|
||||
add_executable(test-${SOURCE_FILENAME} WIN32 ${SOURCE_FILE} ${TEST_RESOURCES})
|
||||
target_link_libraries(test-${SOURCE_FILENAME} PRIVATE glerminallib test-common)
|
||||
endforeach()
|
||||
target_link_libraries(test-${SOURCE_FILENAME} PRIVATE glerminal test-common)
|
||||
endforeach()
|
||||
|
||||
@@ -8,18 +8,18 @@
|
||||
|
||||
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()
|
||||
{
|
||||
// -- DIRTY HACK --
|
||||
//
|
||||
//
|
||||
// GL_TEXTURE_2D is not rebound after setting up screen framebuffer
|
||||
// This code will break if this behavior changes
|
||||
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
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