first stable version OK

This commit is contained in:
VisualGMQ 2022-07-31 22:27:19 +08:00
parent a5213c552a
commit d92247535f
31 changed files with 8950 additions and 71 deletions

7
.gitignore vendored
View File

@ -1,2 +1,7 @@
build build
.vscode .vscode
testExecutor
install
TODO.txt
.cache
compile_flags.txt

2
3rdlibs/stb/stb_image.c Normal file
View File

@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

7873
3rdlibs/stb/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,5 @@
cmake_minimum_required(VERSION 3.15) cmake_minimum_required(VERSION 3.15)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(HazelLuaEngine project(HazelLuaEngine
VERSION 0.1.0 VERSION 0.1.0
DESCRIPTION "a tiny engine made with C and Lua for 1MGames" DESCRIPTION "a tiny engine made with C and Lua for 1MGames"
@ -15,17 +13,35 @@ set(HAZEL_LUA_BRIDGE_NAME hazel)
include(cmake/FindLua.cmake) include(cmake/FindLua.cmake)
include(cmake/FindGLFW.cmake) include(cmake/FindGLFW.cmake)
include(cmake/FindGLAD.cmake) include(cmake/FindGLAD.cmake)
include(cmake/FindSTB.cmake)
# hazel # hazel-core
aux_source_directory(src HAZEL_SRC) aux_source_directory(src HAZEL_SRC)
add_library(${HAZEL_CORE_NAME} STATIC ${HAZEL_SRC}) add_library(${HAZEL_CORE_NAME} SHARED ${HAZEL_SRC})
target_link_libraries(${HAZEL_CORE_NAME} PUBLIC glad glfw) target_link_libraries(${HAZEL_CORE_NAME} PUBLIC glad glfw stb_image)
target_include_directories(${HAZEL_CORE_NAME} PUBLIC .) target_include_directories(${HAZEL_CORE_NAME} PUBLIC .)
target_compile_features(${HAZEL_CORE_NAME} PUBLIC c_std_11) target_compile_features(${HAZEL_CORE_NAME} PUBLIC c_std_11)
target_precompile_headers(${HAZEL_CORE_NAME} PUBLIC hazel/pch.h)
if(WIN32) if(WIN32)
target_compile_definitions(${HAZEL_CORE_NAME} PUBLIC WIN32) target_compile_definitions(${HAZEL_CORE_NAME} PUBLIC WIN32)
endif(WIN32) elseif(APPLE)
target_compile_definitions(${HAZEL_CORE_NAME} PUBLIC APPLE)
endif()
# sandbox # lua
add_subdirectory(binding/lua) add_subdirectory(binding/lua)
# test
add_subdirectory(test)
# install
install(
TARGETS ${HAZEL_LUA_BRIDGE_NAME} lua ${HAZEL_EXECUTOR_NAME} ${HAZEL_CORE_NAME}
DESTINATION ${CMAKE_SOURCE_DIR}/install
)
install(
DIRECTORY shader
DESTINATION ${CMAKE_SOURCE_DIR}/install
)

View File

@ -1,5 +1,6 @@
add_library(${HAZEL_LUA_BRIDGE_NAME} SHARED bridge.c) add_library(${HAZEL_LUA_BRIDGE_NAME} SHARED bridge.c)
target_link_libraries(${HAZEL_LUA_BRIDGE_NAME} PUBLIC ${HAZEL_CORE_NAME} lua) target_link_libraries(${HAZEL_LUA_BRIDGE_NAME} PUBLIC ${HAZEL_CORE_NAME} lua)
target_precompile_headers(${HAZEL_LUA_BRIDGE_NAME} REUSE_FROM ${HAZEL_CORE_NAME})
add_executable(${HAZEL_EXECUTOR_NAME} executor.c) add_executable(${HAZEL_EXECUTOR_NAME} executor.c)
target_link_libraries(${HAZEL_EXECUTOR_NAME} PUBLIC lua) target_link_libraries(${HAZEL_EXECUTOR_NAME} PUBLIC lua ${HAZEL_CORE_NAME})

View File

@ -4,18 +4,182 @@
#include "luaconf.h" #include "luaconf.h"
#include "hazel/hazel.h" #include "hazel/hazel.h"
#include "hazel/renderer.h"
static int LuaBridge_RunExampleWindow(lua_State* L) { static int LuaBridge_RenderSetClearColor(lua_State* L) {
Hazel_RunExampleWindow(); float r = luaL_checknumber(L, 1);
float g = luaL_checknumber(L, 2);
float b = luaL_checknumber(L, 3);
float a = luaL_checknumber(L, 4);
Hazel_RenderSetClearColor(r, g, b, a);
return 0; return 0;
} }
static const struct luaL_Reg hazel[] = { static int LuaBridge_SayHello(lua_State* L) {
{"RunExampleWindow", LuaBridge_RunExampleWindow}, printf("Hello Hazel\n");
return 0;
}
static int LuaBridge_RenderClear(lua_State* L) {
Hazel_RenderClear();
return 0;
}
static int LuaBridge_RenderSetDrawColor(lua_State* L) {
float r = luaL_checknumber(L, 1);
float g = luaL_checknumber(L, 2);
float b = luaL_checknumber(L, 3);
float a = luaL_checknumber(L, 4);
Hazel_RenderSetDrawColor(r, g, b, a);
return 0;
}
static int LuaBridge_RenderDrawLine(lua_State* L) {
float x1 = luaL_checknumber(L, 1);
float y1 = luaL_checknumber(L, 2);
float x2 = luaL_checknumber(L, 3);
float y2 = luaL_checknumber(L, 4);
Hazel_RenderDrawLine(x1, y1, x2, y2);
return 0;
}
static int LuaBridge_RenderDrawRect(lua_State* L) {
float x = luaL_checknumber(L, 1);
float y = luaL_checknumber(L, 2);
float w = luaL_checknumber(L, 3);
float h = luaL_checknumber(L, 4);
Hazel_RenderDrawRect(x, y, w, h);
return 0;
}
static int LuaBridge_RenderFillRect(lua_State* L) {
float x = luaL_checknumber(L, 1);
float y = luaL_checknumber(L, 2);
float w = luaL_checknumber(L, 3);
float h = luaL_checknumber(L, 4);
Hazel_RenderFillRect(x, y, w, h);
return 0;
}
static int LuaBridge_LoadTexture(lua_State* L) {
const char* filename = luaL_checkstring(L, 1);
Hazel_Texture* texture = Hazel_LoadTexture(filename);
lua_pushlightuserdata(L, texture);
return 1;
}
static int LuaBridge_DestroyTexture(lua_State* L) {
Hazel_Texture* texture = (Hazel_Texture*)lua_topointer(L, 1);
Hazel_DestroyTexture(texture);
return 0;
}
static int LuaBridge_TextureGetSize(lua_State* L) {
Hazel_Texture* texture = (Hazel_Texture*)lua_topointer(L, 1);
int w, h;
Hazel_TextureGetSize(texture, &w, &h);
lua_pushnumber(L, w);
lua_pushnumber(L, h);
return 2;
}
static int LuaBridge_RenderDrawTexture(lua_State* L) {
Hazel_Texture* texture = (Hazel_Texture*)lua_topointer(L, 1);
int rx = luaL_checknumber(L, 2);
int ry = luaL_checknumber(L, 3);
int rw = luaL_checknumber(L, 4);
int rh = luaL_checknumber(L, 5);
int dx = luaL_checknumber(L, 6);
int dy = luaL_checknumber(L, 7);
int dw = luaL_checknumber(L, 8);
int dh = luaL_checknumber(L, 9);
Hazel_RenderFlip flip = luaL_checknumber(L, 10);
Hazel_RenderDrawTexture(texture, rx, ry, rw, rh, dx, dy, dw, dh, flip);
return 0;
}
static int LuaBridge_GetCanvaSize(lua_State* L) {
int w, h;
Hazel_GetCanvaSize(&w, &h);
lua_pushnumber(L, w);
lua_pushnumber(L, h);
return 2;
}
static int LuaBridge_WindowSetIcon(lua_State* L) {
const char* filename = luaL_checkstring(L, 1);
Hazel_WindowSetIcon(filename);
return 0;
}
static int LuaBridge_GetKeyState(lua_State* L) {
int key = luaL_checkinteger(L, 1);
lua_pushnumber(L, Hazel_GetKeyState(key));
return 1;
}
static int LuaBridge_GetMousePos(lua_State* L) {
double x, y;
Hazel_GetMousePos(&x, &y);
lua_pushnumber(L, x);
lua_pushnumber(L, y);
return 2;
}
static int LuaBridge_GetMouseButtonState(lua_State* L) {
int btn = luaL_checknumber(L, 1);
lua_pushnumber(L, Hazel_GetMouseBtnState(btn));
return 1;
}
static int LuaBridge_GetTime(lua_State* L) {
lua_pushnumber(L, Hazel_GetTime());
return 1;
}
static int LuaBridge_GetWindowSize(lua_State* L) {
int w, h;
Hazel_WindowGetSize(&w, &h);
lua_pushnumber(L, w);
lua_pushnumber(L, h);
return 2;
}
static int LuaBridge_HideCursor() {
Hazel_HideCursor();
return 0;
}
static int LuaBridge_ShowCursor() {
Hazel_ShowCursor();
return 0;
}
static const struct luaL_Reg libhazel[] = {
{"RenderSetClearColor", LuaBridge_RenderSetClearColor},
{"RenderSetDrawColor", LuaBridge_RenderSetDrawColor},
{"RenderClear", LuaBridge_RenderClear},
{"RenderDrawLine", LuaBridge_RenderDrawLine},
{"RenderDrawRect", LuaBridge_RenderDrawRect},
{"RenderFillRect", LuaBridge_RenderFillRect},
{"RenderDrawTexture", LuaBridge_RenderDrawTexture},
{"TextureGetSize", LuaBridge_TextureGetSize},
{"LoadTexture", LuaBridge_LoadTexture},
{"DestroyTexture", LuaBridge_DestroyTexture},
{"GetCanvaSize", LuaBridge_GetCanvaSize},
{"WindowSetIcon", LuaBridge_WindowSetIcon},
{"GetTime", LuaBridge_GetTime},
{"GetWindowSize", LuaBridge_GetWindowSize},
{"GetMousePos", LuaBridge_GetMousePos},
{"GetMouseButtonState", LuaBridge_GetMouseButtonState},
{"GetKeyState", LuaBridge_GetKeyState},
{"HideCursor", LuaBridge_HideCursor},
{"ShowCursor", LuaBridge_ShowCursor},
{"SayHello", LuaBridge_SayHello},
{NULL, NULL}, {NULL, NULL},
}; };
DLLEXPORT int luaopen_hazel(lua_State* L) { DLLEXPORT int luaopen_libhazel(lua_State* L) {
luaL_newlib(L, hazel); luaL_newlib(L, libhazel);
return 1; return 1;
} }

View File

@ -2,19 +2,184 @@
#include "lualib.h" #include "lualib.h"
#include "lauxlib.h" #include "lauxlib.h"
int main() { #include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "hazel/hazel.h"
typedef struct {
int WindowWidth;
int WindowHeight;
char WindowTitle[1024];
char LuaEntryFile[1024];
} Config;
int getNumber(lua_State* L, const char* name, int* num) {
int isnum;
lua_getglobal(L, name);
*num = (int)lua_tointegerx(L, -1, &isnum);
if (!isnum) {
printf("Please check your %s field", name);
return 0;
}
return 1;
}
int getString(lua_State* L, const char* name, char* str) {
lua_getglobal(L, name);
const char* s = lua_tostring(L, -1);
if (!s) {
printf("Please check your %s filed", name);
lua_close(L);
return 0;
}
strcpy(str, s);
return 1;
}
const char* LuaConfigFileTemplate =
"WindowWidth = 800\n"
"WindowHeight = 600\n"
"Title = \"LuaTinyEngine\"\n"
"EntryFile = \"main.lua\"";
void createLuaConfigFile() {
FILE* file = fopen("config.lua", "w+");
if (!file) {
printf("can't open file config.lua");
return ;
}
fputs(LuaConfigFileTemplate, file);
fclose(file);
}
const char* LuaEntryFileTemplate =
"local hazel = require \"hazel\"\n"
"\n"
"function GameStart()\n"
" hazel.SayHello()\n"
"end\n"
"\n"
"function GameLoop()\n"
"end\n"
"\n"
"function GameQuit()\n"
"end";
void createLuaEntryFile() {
FILE* file = fopen("main.lua", "w+");
if (!file) {
printf("can't open file main.lua");
return ;
}
fseek(file, 0, SEEK_END);
long size = ftell(file);
if (size <= 0) {
fputs(LuaEntryFileTemplate, file);
fclose(file);
}
}
int ReadConfig(Config* config) {
if (!config) {
printf("please give me a valid config");
return 0;
}
lua_State* L = luaL_newstate(); lua_State* L = luaL_newstate();
if (!L) {
printf("Fatal Error, create lua stack failed");
return 1;
}
if (luaL_loadfile(L, "config.lua") != 0) {
printf("You don't have a config.lua, create one for you.Modify it to your config.");
createLuaConfigFile();
goto ERR_HANDLE;
}
if (lua_pcall(L, 0, 0, 0) != 0) {
printf("pcall config file failed");
goto ERR_HANDLE;
}
if (!getNumber(L, "WindowWidth", &config->WindowWidth)) {
goto ERR_HANDLE;
}
if (!getNumber(L, "WindowHeight", &config->WindowHeight)) {
goto ERR_HANDLE;
}
if (!getString(L, "Title", config->WindowTitle)) {
goto ERR_HANDLE;
}
if (!getString(L, "EntryFile", config->LuaEntryFile)) {
goto ERR_HANDLE;
}
lua_close(L);
return 1;
ERR_HANDLE:
lua_close(L);
return 0;
}
lua_State* L = NULL;
void GameStart() {
lua_getglobal(L, "GameStart");
if (lua_pcall(L, 0, 0, 0)) {
GAME_LOG_ERROR("call GameStart function in lua failed");
const char* error = luaL_checkstring(L, -1);
GAME_LOG_ERROR("[Lua Error]: %s", error);
}
}
void GameLoop() {
lua_getglobal(L, "GameLoop");
if (lua_pcall(L, 0, 0, 0)) {
GAME_LOG_ERROR("call GameLoop function in lua failed");
const char* error = luaL_checkstring(L, -1);
GAME_LOG_ERROR("[Lua Error]: %s", error);
}
}
void GameQuit() {
lua_getglobal(L, "GameQuit");
if (lua_pcall(L, 0, 0, 0)) {
GAME_LOG_ERROR("call GameQuit function in lua failed");
const char* error = luaL_checkstring(L, -1);
GAME_LOG_ERROR("[Lua Error]: %s", error);
}
}
int main() {
Config config;
if (!ReadConfig(&config)) {
return 1;
}
L = luaL_newstate();
if (!L) { if (!L) {
printf("lua init failed\n"); printf("lua init failed\n");
return 1; return 1;
} }
luaL_openlibs(L); luaL_openlibs(L);
if (luaL_loadfile(L, "main.lua") || lua_pcall(L, 0, 0, 0)) { if (luaL_loadfile(L, config.LuaEntryFile)) {
printf("main.lua load and execute failed\n"); createLuaEntryFile();
ENGINE_LOG_CRITICAL("%s load and execute failed, create main.lua for you\n", config.LuaEntryFile);
}
if (lua_pcall(L, 0, 0, 0)) {
ENGINE_LOG_ERROR("[Lua Error]: %s", luaL_checkstring(L, 1));
return 1; return 1;
} }
Hazel_Init(config.WindowTitle, config.WindowWidth, config.WindowHeight);
Hazel_RegistGameFuncs(GameStart, GameLoop, GameQuit);
Hazel_Run();
Hazel_Quit();
lua_close(L); lua_close(L);
return 0; return 0;
} }

View File

@ -1,5 +0,0 @@
---@class hazel
---@field RunExampleWindow function
local hazel = require "hazel"
hazel.RunExampleWindow()

View File

@ -1,3 +1,3 @@
aux_source_directory(3rdlibs/glad/src GLAD_SRC) aux_source_directory(3rdlibs/glad/src GLAD_SRC)
add_library(glad STATIC ${GLAD_SRC}) add_library(glad STATIC ${GLAD_SRC})
target_include_directories(glad PUBLIC 3rdlibs/glad/include) target_include_directories(glad PUBLIC 3rdlibs/glad/include)

View File

@ -33,7 +33,7 @@ set(LUA_SRC
3rdlibs/lua/src/linit.c 3rdlibs/lua/src/linit.c
) )
add_library(lua STATIC ${LUA_SRC}) add_library(lua SHARED ${LUA_SRC})
target_include_directories(lua PUBLIC ./3rdlibs/lua/src) target_include_directories(lua PUBLIC ./3rdlibs/lua/src)
target_compile_features(lua PRIVATE c_std_99) target_compile_features(lua PRIVATE c_std_99)
@ -41,4 +41,4 @@ target_compile_features(lua PRIVATE c_std_99)
# target_compile_options(lua PRIVATE LUA_USE_LINUX) # target_compile_options(lua PRIVATE LUA_USE_LINUX)
if (NOT WIN32) if (NOT WIN32)
target_compile_options(lua PRIVATE LUA_USE_LINUX) target_compile_options(lua PRIVATE LUA_USE_LINUX)
endif() endif()

2
cmake/FindSTB.cmake Normal file
View File

@ -0,0 +1,2 @@
add_library(stb_image STATIC 3rdlibs/stb/stb_image.c)
target_include_directories(stb_image PUBLIC 3rdlibs/stb)

10
hazel/dllexport.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __HAZEL_DLLEXPORT_H__
#define __HAZEL_DLLEXPORT_H__
#ifdef WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
#endif

19
hazel/glhelper.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef __HAZEL_GLHELPER_H__
#define __HAZEL_GLHELPER_H__
#include "glad/glad.h"
#define TRY_GET_GL_ERROR_MAX_LOOP 10000
const char* GLGetErrorString(GLenum);
void GLClearError();
#define GL_CALL(statement) do { \
GLClearError(); \
statement; \
GLenum ___err_inner_use = glGetError(); \
if (___err_inner_use != GL_NO_ERROR) { GL_LOG_ERROR("%s", GLGetErrorString(___err_inner_use)); } \
} while(0)
#endif

View File

@ -2,7 +2,28 @@
#define __HAZEL_HAZEL_H__ #define __HAZEL_HAZEL_H__
#include "pch.h" #include "pch.h"
#include "window.h"
#include "renderer.h"
DLLEXPORT void Hazel_RunExampleWindow(); typedef void(*Hazel_BeforeGameStartFunc)(void);
typedef void(*Hazel_GameLoopFunc)(void);
typedef void(*Hazel_BeforeGameQuitFunc)(void);
typedef void(*Hazel_KeyInputFunc)(GLFWwindow*, int, int, int, int);
typedef void(*Hazel_MousePosInputFunc)(GLFWwindow*, double, double);
typedef void(*Hazel_MouseButtonInputFunc)(GLFWwindow*, int, int , int);
#endif DLLEXPORT void Hazel_Init(const char* title, int w, int h);
DLLEXPORT void Hazel_Quit();
DLLEXPORT int Hazel_ShouldClose();
DLLEXPORT void Hazel_Run();
DLLEXPORT void Hazel_RegistGameFuncs(Hazel_BeforeGameStartFunc, Hazel_GameLoopFunc, Hazel_BeforeGameQuitFunc);
DLLEXPORT void Hazel_RegistInputFuncs(Hazel_KeyInputFunc, Hazel_MousePosInputFunc, Hazel_MouseButtonInputFunc);
DLLEXPORT int Hazel_GetKeyState(int key);
DLLEXPORT int Hazel_GetMouseBtnState(int btn);
DLLEXPORT void Hazel_SetCursorPos(double x, double y);
DLLEXPORT void Hazel_GetMousePos(double* x, double* y);
DLLEXPORT double Hazel_GetTime();
DLLEXPORT void Hazel_HideCursor();
DLLEXPORT void Hazel_ShowCursor();
#endif

23
hazel/log.h Normal file
View File

@ -0,0 +1,23 @@
#include <stdio.h>
#include <string.h>
#include "dllexport.h"
DLLEXPORT const char* GetFilename(const char* fullpath);
#define ENGINE_LOG_CRITICAL(fmt, ...) do {printf("[Engine Critical][%d]%s - %s]: " fmt "\n", __LINE__, GetFilename(__FILE__), __FUNCTION__, ##__VA_ARGS__); fflush(stdout), exit(1); } while(0)
#define ENGINE_LOG_ERROR(fmt, ...) do {printf("[Engine Error][%d][%s - %s]: " fmt "\n", __LINE__, GetFilename(__FILE__), __FUNCTION__, ##__VA_ARGS__); fflush(stdout); } while(0)
#define ENGINE_LOG_INFO(fmt, ...) do {printf("[Engine Info][%d][%s - %s]: " fmt "\n", __LINE__, GetFilename(__FILE__), __FUNCTION__, ##__VA_ARGS__); fflush(stdout); } while(0)
#define ENGINE_LOG_WARN(fmt, ...) do {printf("[Engine Warn][%d][%s - %s]: " fmt "\n", __LINE__, GetFilename(__FILE__), __FUNCTION__, ##__VA_ARGS__); fflush(stdout); } while(0)
#define ENGINE_LOG_DEBUG(fmt, ...) do {printf("[Engine Debug][%d][%s - %s]: " fmt "\n", __LINE__, GetFilename(__FILE__), __FUNCTION__, ##__VA_ARGS__); fflush(stdout); } while(0)
#define GL_LOG_CRITICAL(fmt, ...) do {printf("[GL Critical][%d][%s - %s]: " fmt "\n", __LINE__, GetFilename(__FILE__), __FUNCTION__, ##__VA_ARGS__); fflush(stdout); exit(1); } while(0)
#define GL_LOG_ERROR(fmt, ...) do {printf("[GL Error][%d][%s - %s]: " fmt "\n", __LINE__, __FUNCTION__, GetFilename(__FILE__), ##__VA_ARGS__); fflush(stdout);} while(0)
#define GL_LOG_INFO(fmt, ...) do {printf("[GL Info][%d][%s - %s]: " fmt "\n", __LINE__, __FUNCTION__, GetFilename(__FILE__), ##__VA_ARGS__); fflush(stdout);} while(0)
#define GL_LOG_WARN(fmt, ...) do {printf("[GL Warn][%d][%s - %s]: " fmt "\n", __LINE__, __FUNCTION__, GetFilename(__FILE__), ##__VA_ARGS__); fflush(stdout);} while(0)
#define GL_LOG_DEBUG(fmt, ...) do {printf("[GL Debug][%d][%s - %s]: " fmt "\n", __LINE__, __FUNCTION__, GetFilename(__FILE__), ##__VA_ARGS__); fflush(stdout);} while(0)
#define GAME_LOG_CRITICAL(fmt, ...) do {printf("[Game Critical][%d][%s - %s]: " fmt "\n", __LINE__, __FUNCTION__, ##__VA_ARGS__); fflush(stdout); } while(0)
#define GAME_LOG_ERROR(fmt, ...) do {printf("[Game Error][%d][%s - %s]: " fmt "\n", __LINE__, __FUNCTION__, GetFilename(__FILE__), ##__VA_ARGS__); fflush(stdout);} while(0)
#define GAME_LOG_INFO(fmt, ...) do {printf("[Game Info][%d][%s - %s]: " fmt "\n", __LINE__, __FUNCTION__, GetFilename(__FILE__), ##__VA_ARGS__); fflush(stdout);} while(0)
#define GAME_LOG_WARN(fmt, ...) do {printf("[Game Warn][%d][%s - %s]: " fmt "\n", __LINE__, __FUNCTION__, GetFilename(__FILE__), ##__VA_ARGS__); fflush(stdout);} while(0)
#define GAME_LOG_DEBUG(fmt, ...) do {printf("[Game Debug][%d][%s - %s]: " fmt "\n", __LINE__, __FUNCTION__, GetFilename(__FILE__), ##__VA_ARGS__); fflush(stdout);} while(0)

View File

@ -4,16 +4,13 @@
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
#include "GLFW/glfw3.h" #include "GLFW/glfw3.h"
#include "glad/glad.h" #include "stb_image.h"
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <math.h>
#include "log.h"
#include "glhelper.h"
#include "dllexport.h"
#ifdef WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif #endif
#endif

31
hazel/renderer.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef __HAZEL_RENDERER_H__
#define __HAZEL_RENDERER_H__
#include "pch.h"
#include "texture.h"
typedef enum {
FLIP_NONE = 0x00,
FLIP_HORIZONTAL = 0x01,
FLIP_VERTICAL = 0x02,
FLIP_BOTH = FLIP_HORIZONTAL | FLIP_VERTICAL,
} Hazel_RenderFlip;
DLLEXPORT void Hazel_RenderInit(int w, int h);
DLLEXPORT void Hazel_RenderQuit();
DLLEXPORT void Hazel_RenderSetClearColor(float r, float g, float b, float a);
DLLEXPORT void Hazel_RenderClear();
DLLEXPORT void Hazel_RenderSetDrawColor(float r, float g, float b, float a);
DLLEXPORT void Hazel_RenderSetViewport(int x, int y, int w, int h);
DLLEXPORT void Hazel_RenderDrawLine(int x1, int y1, int x2, int y2);
DLLEXPORT void Hazel_RenderDrawRect(int x, int y, int w, int h);
DLLEXPORT void Hazel_RenderFillRect(int x, int y, int w, int h);
DLLEXPORT void Hazel_RenderDrawTexture(Hazel_Texture *texture,
int rx, int ry, int rw, int rh,
int dx, int dy, int dw, int dh,
Hazel_RenderFlip);
#endif

19
hazel/texture.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef __HAZEL_TEXTURE_H__
#define __HAZEL_TEXTURE_H__
#include "pch.h"
struct Hazel_Texture;
typedef struct Hazel_Texture Hazel_Texture;
DLLEXPORT Hazel_Texture* Hazel_LoadTexture(const char* filename);
DLLEXPORT Hazel_Texture* Hazel_CreateTexture(const unsigned char* data, int w, int h);
DLLEXPORT void Hazel_DestroyTexture(Hazel_Texture*);
DLLEXPORT void Hazel_TextureGetSize(Hazel_Texture*, int* w, int* h);
DLLEXPORT void Hazel_TextureSetAlpha(Hazel_Texture*, float);
DLLEXPORT void Hazel_TextureSetColor(Hazel_Texture*, float r, float g, float b);
DLLEXPORT float Hazel_TextureGetAlpha(Hazel_Texture*);
DLLEXPORT void Hazel_TextureGetColor(Hazel_Texture*, float* r, float* g, float* b);
void Hazel_BindTexture(Hazel_Texture*);
#endif

13
hazel/window.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __HAZEL_WINDOW_H__
#define __HAZEL_WINDOW_H__
#include "pch.h"
extern GLFWwindow* window;
int Hazel_InitWindow(const char* title, int width, int height);
DLLEXPORT void Hazel_WindowGetSize(int* w, int* h);
DLLEXPORT void Hazel_GetCanvaSize(int* w, int* h);
DLLEXPORT void Hazel_WindowSetIcon(const char* filename);
#endif

12
shader/shader.frag Normal file
View File

@ -0,0 +1,12 @@
#version 330 core
in vec2 Texcoord;
out vec4 FragColor;
uniform vec4 Color;
uniform sampler2D Texture;
void main() {
FragColor = Color * texture(Texture, Texcoord);
}

13
shader/shader.vert Normal file
View File

@ -0,0 +1,13 @@
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexcoord;
out vec2 Texcoord;
uniform mat4 Project;
void main() {
Texcoord = aTexcoord;
gl_Position = Project * vec4(aPos, 0, 1);
}

21
src/glhelper.c Normal file
View File

@ -0,0 +1,21 @@
#include "hazel/glhelper.h"
void GLClearError() {
int loop = 0;
while (loop < TRY_GET_GL_ERROR_MAX_LOOP && glGetError() != GL_NO_ERROR) { loop++; }
}
#define CASE(e) case e: return #e;
const char* GLGetErrorString(GLenum err) {
switch (err) {
CASE(GL_NO_ERROR)
CASE(GL_INVALID_ENUM)
CASE(GL_INVALID_VALUE)
CASE(GL_INVALID_OPERATION)
CASE(GL_OUT_OF_MEMORY)
CASE(GL_INVALID_FRAMEBUFFER_OPERATION)
default:
return "Unknown Error";
}
}

View File

@ -1,37 +1,82 @@
#include "hazel/hazel.h" #include "hazel/hazel.h"
void Hazel_RunExampleWindow() { Hazel_GameLoopFunc gameLoopCallback = NULL;
GLFWwindow* window; Hazel_BeforeGameStartFunc beforeGameStartCallback = NULL;
Hazel_BeforeGameQuitFunc beforeGameQuitCallback = NULL;
/* Initialize the library */ void Hazel_Init(const char* title, int w, int h) {
if (!glfwInit()) Hazel_InitWindow(title, w, h);
return; Hazel_RenderInit(w, h);
}
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window) {
glfwTerminate();
return;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
/* Use Glad to load OpenGL */
gladLoadGL();
glClearColor(0.1, 0.1, 0.1, 1);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window)) {
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
void Hazel_Quit() {
Hazel_RenderQuit();
glfwTerminate(); glfwTerminate();
}
int Hazel_ShouldClose() {
return glfwWindowShouldClose(window);
}
void Hazel_RegistGameFuncs(Hazel_BeforeGameStartFunc before, Hazel_GameLoopFunc doing, Hazel_BeforeGameQuitFunc after) {
beforeGameStartCallback = before;
gameLoopCallback = doing;
beforeGameQuitCallback = after;
}
void Hazel_Run() {
if (beforeGameStartCallback) {
beforeGameStartCallback();
}
while (!Hazel_ShouldClose()) {
glfwPollEvents();
if (gameLoopCallback) {
gameLoopCallback();
}
glfwSwapBuffers(window);
}
if (beforeGameQuitCallback) {
beforeGameQuitCallback();
}
}
double Hazel_GetTime() {
return glfwGetTime();
}
void Hazel_RegistInputFuncs(Hazel_KeyInputFunc keyInput,
Hazel_MousePosInputFunc mousePosInput,
Hazel_MouseButtonInputFunc mouseBtnInput) {
glfwSetKeyCallback(window, keyInput);
glfwSetCursorPosCallback(window, mousePosInput);
glfwSetMouseButtonCallback(window, mouseBtnInput);
}
int Hazel_GetKeyState(int key) {
return glfwGetKey(window, key);
}
void Hazel_GetMousePos(double* x, double* y) {
glfwGetCursorPos(window, x, y);
}
void Hazel_SetCursorPos(double x, double y) {
glfwSetCursorPos(window, x, y);
}
int Hazel_GetMouseBtnState(int btn) {
return glfwGetMouseButton(window, btn);
}
void Hazel_HideCursor() {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}
void Hazel_ShowCursor() {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
} }

7
src/log.c Normal file
View File

@ -0,0 +1,7 @@
#include "hazel/log.h"
const char* GetFilename(const char* fullpath) {
const char* ptr = fullpath + strlen(fullpath);
while (*ptr != '/' && *ptr != '\\' && ptr != fullpath) ptr--;
return ptr == fullpath ? ptr : ptr + 1;
}

239
src/renderer.c Normal file
View File

@ -0,0 +1,239 @@
#include "hazel/renderer.h"
struct {
GLuint shader, vbo, vao;
Hazel_Texture* whiteTexture;
float currentR, currentG, currentB, currentA;
} RenderContext;
void loadFile(const char* filename, char* buf) {
FILE* file = fopen(filename, "r+");
if (!file) {
fclose(file);
ENGINE_LOG_CRITICAL("shader file %s load failed", filename);
}
fseek(file, 0, SEEK_END);
long len = ftell(file);
rewind(file);
len = fread(buf, 1, len, file);
buf[len] = '\0';
fclose(file);
}
GLuint createShader() {
int bufSize = sizeof(GLchar) * 1024;
GLchar* buf = malloc(bufSize);
memset(buf, 0, bufSize);
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
loadFile("shader/shader.vert", buf);
GL_CALL(glShaderSource(vertexShader, 1, &buf, NULL));
GL_CALL(glCompileShader(vertexShader));
int success;
char infoLog[1024];
GL_CALL(glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success));
if (!success) {
glGetShaderInfoLog(vertexShader, sizeof(infoLog), NULL, infoLog);
ENGINE_LOG_ERROR("vertex shader compile error:\n%s", infoLog);
}
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
loadFile("shader/shader.frag", buf);
GL_CALL(glShaderSource(fragShader, 1, &buf, NULL));
GL_CALL(glCompileShader(fragShader));
GL_CALL(glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success));
if (!success) {
GL_CALL(glGetShaderInfoLog(fragShader, sizeof(infoLog), NULL, infoLog));
ENGINE_LOG_ERROR("fragment shader compile error:\n%s", infoLog);
}
GLuint shader = glCreateProgram();
GL_CALL(glAttachShader(shader, vertexShader));
GL_CALL(glAttachShader(shader, fragShader));
GL_CALL(glLinkProgram(shader));
GL_CALL(glGetProgramiv(shader, GL_LINK_STATUS, &success));
if(!success) {
GL_CALL(glGetProgramInfoLog(shader, sizeof(infoLog), NULL, infoLog));
ENGINE_LOG_ERROR("shader link error:\n%s", infoLog);
}
GL_CALL(glDeleteShader(vertexShader));
GL_CALL(glDeleteShader(fragShader));
return shader;
}
void setProjectUniform(int w, int h) {
float left = 0, right = w, top = 0, bottom = h, near = -1, far = 1;
float projectMat[] = {
2 / (right - left), 0, 0, 0,
0, 2 / (top - bottom), 0, 0,
0, 0, 2 / (near - far), 0,
(right + left) / (left - right), (top + bottom) / (bottom - top), (near + far) / (far - near), 1,
};
GLint loc = glGetUniformLocation(RenderContext.shader, "Project");
if (loc < 0) {
ENGINE_LOG_ERROR("shader uniform variable Project not found");
}
GL_CALL(glUniformMatrix4fv(loc, 1, GL_FALSE, projectMat));
}
void initBuffer() {
GL_CALL(glGenBuffers(1, &RenderContext.vbo));
if (RenderContext.vbo == 0) {
ENGINE_LOG_CRITICAL("vertex buffer create failed");
}
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, RenderContext.vbo));
}
void initVertexArray() {
GL_CALL(glGenVertexArrays(1, &RenderContext.vao));
if (RenderContext.vao == 0) {
ENGINE_LOG_CRITICAL("vertex array create failed");
}
GL_CALL(glBindVertexArray(RenderContext.vao));
GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0));
GL_CALL(glEnableVertexAttribArray(0));
GL_CALL(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))));
GL_CALL(glEnableVertexAttribArray(1));
}
void Hazel_RenderInit(int w, int h) {
RenderContext.shader = createShader();
GL_CALL(glUseProgram(RenderContext.shader));
setProjectUniform(w, h);
initBuffer();
initVertexArray();
unsigned char data[] = {255, 255, 255, 255};
RenderContext.whiteTexture = Hazel_CreateTexture((void*)data, 1, 1);
GL_CALL(glActiveTexture(GL_TEXTURE0));
Hazel_RenderSetDrawColor(1, 1, 1, 1);
GL_CALL(glEnable(GL_BLEND));
GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
}
void Hazel_RenderQuit() {
Hazel_DestroyTexture(RenderContext.whiteTexture);
GL_CALL(glDeleteProgram(RenderContext.shader));
GL_CALL(glDeleteBuffers(1, &RenderContext.vbo));
GL_CALL(glDeleteVertexArrays(1, &RenderContext.vao));
}
void Hazel_RenderSetClearColor(float r, float g, float b, float a) {
GL_CALL(glClearColor(r, g, b, a));
}
void Hazel_RenderSetDrawColor(float r, float g, float b, float a) {
if (RenderContext.currentR == r &&
RenderContext.currentG == g &&
RenderContext.currentB == b &&
RenderContext.currentA == a) {
return;
}
GLint loc = glGetUniformLocation(RenderContext.shader, "Color");
if (loc < 0) {
ENGINE_LOG_ERROR("shader uniform variable Color not found");
return;
}
GL_CALL(glUniform4f(loc, r, g, b, a));
RenderContext.currentR = r;
RenderContext.currentG = g;
RenderContext.currentB = b;
RenderContext.currentA = a;
}
void Hazel_RenderClear() {
GL_CALL(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT));
}
void Hazel_RenderSetViewport(int x, int y, int w, int h) {
GL_CALL(glViewport(x, y, w, h));
}
void Hazel_RenderDrawLine(int x1, int y1, int x2, int y2) {
Hazel_BindTexture(RenderContext.whiteTexture);
float vertices[] = {
x1, y1, 0, 0,
x2, y2, 0, 0,
};
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
GL_CALL(glDrawArrays(GL_LINES, 0, 2));
}
void Hazel_RenderDrawRect(int x, int y, int w, int h) {
Hazel_BindTexture(RenderContext.whiteTexture);
float vertices[] = {
x, y, 0, 0,
x + w, y, 0, 0,
x + w, y + h, 0, 0,
x, y + h, 0, 0,
};
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
GL_CALL(glDrawArrays(GL_LINE_LOOP, 0, 4));
}
void Hazel_RenderFillRect(int x, int y, int w, int h) {
Hazel_BindTexture(RenderContext.whiteTexture);
float vertices[] = {
x, y, 0, 0,
x + w, y, 0, 0,
x + w, y + h, 0, 0,
x, y, 0, 0,
x + w, y + h, 0, 0,
x, y + h, 0, 0,
};
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
GL_CALL(glDrawArrays(GL_TRIANGLES, 0, 6));
}
void swap(float* v1, float* v2) {
float tmp = *v1;
*v1 = *v2;
*v2 = tmp;
}
void Hazel_RenderDrawTexture(Hazel_Texture* texture,
int rx, int ry, int rw, int rh,
int dx, int dy, int dw, int dh,
Hazel_RenderFlip flip) {
if (!texture) return;
float r, g, b, a = Hazel_TextureGetAlpha(texture);
Hazel_TextureGetColor(texture, &r, &g, &b);
Hazel_RenderSetDrawColor(r, g, b, a);
Hazel_BindTexture(texture);
int w, h;
Hazel_TextureGetSize(texture, &w, &h);
float p1x = dx, p1y = dy,
p2x = dx + dw, p2y = dy,
p3x = dx + dw, p3y = dy + dh,
p4x = dx, p4y = dy + dh;
if (flip & FLIP_HORIZONTAL) {
swap(&p1x, &p2x);
swap(&p3x, &p4x);
}
if (flip & FLIP_VERTICAL) {
swap(&p1y, &p3y);
swap(&p2y, &p4y);
}
float vertices[] = {
p1x, p1y, rx / (float)w, ry / (float)h,
p2x, p2y, (rx + rw) / (float)w, ry / (float)h,
p3x, p3y, (rx + rw) / (float)w, (ry + rh) / (float)h,
p1x, p1y, rx / (float)w, ry / (float)h,
p3x, p3y, (rx + rw) / (float)w, (ry + rh) / (float)h,
p4x, p4y, rx / (float)w, (ry + rh) / (float)h,
};
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
GL_CALL(glDrawArrays(GL_TRIANGLES, 0, 6));
}

83
src/texture.c Normal file
View File

@ -0,0 +1,83 @@
#include "hazel/texture.h"
struct Hazel_Texture {
GLuint id;
int w;
int h;
float r, g, b, a;
};
Hazel_Texture* Hazel_LoadTexture(const char* filename) {
int w, h, channel;
unsigned char* data = stbi_load(filename, &w, &h, &channel, 4);
if (!data) {
ENGINE_LOG_ERROR("load %s failed", filename);
return NULL;
}
Hazel_Texture* texture = Hazel_CreateTexture(data, w, h);
stbi_image_free(data);
return texture;
}
void Hazel_TextureSetAlpha(Hazel_Texture* texture, float alpha) {
if (!texture) return;
texture->a = alpha;
}
void Hazel_TextureSetColor(Hazel_Texture* texture, float r, float g, float b) {
if (!texture) return;
texture->r = r;
texture->g = g;
texture->b = b;
}
Hazel_Texture* Hazel_CreateTexture(const unsigned char* data, int w, int h) {
Hazel_Texture* result = (Hazel_Texture*)malloc(sizeof(Hazel_Texture));
result->w = w;
result->h = h;
result->r = 1;
result->g = 1;
result->b = 1;
result->a = 1;
GL_CALL(glGenTextures(1, &result->id));
GL_CALL(glBindTexture(GL_TEXTURE_2D, result->id));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data));
return result;
}
void Hazel_DestroyTexture(Hazel_Texture* texture) {
if (texture) {
GL_CALL(glDeleteTextures(1, &texture->id));
free(texture);
}
}
void Hazel_TextureGetSize(Hazel_Texture* texture, int* w, int* h) {
if (texture) {
if (w) *w = texture->w;
if (h) *h = texture->h;
} else {
if (w) *w = 0;
if (h) *h = 0;
}
}
void Hazel_BindTexture(Hazel_Texture* texture) {
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture ? texture->id : 0));
}
float Hazel_TextureGetAlpha(Hazel_Texture* texture) {
return texture ? texture->a : -1;
}
void Hazel_TextureGetColor(Hazel_Texture* texture, float* r, float* g, float* b) {
if (texture) {
if (r) *r = texture->r;
if (g) *g = texture->g;
if (b) *b = texture->b;
}
}

60
src/window.c Normal file
View File

@ -0,0 +1,60 @@
#include "hazel/window.h"
GLFWwindow* window = NULL;
int canvaW = 0, canvaH = 0;
void Hazel_GetCanvaSize(int* w, int* h) {
if (w) *w = canvaW;
if (h) *h = canvaH;
}
void windowResizeCallback(GLFWwindow* window, int width, int height) {
GL_CALL(glViewport(0, 0, width, height));
}
int Hazel_InitWindow(const char* title, int width, int height) {
if (!glfwInit()) {
GAME_LOG_CRITICAL("glfw init failed");
return 0;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef APPLE
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
window = glfwCreateWindow(width, height, title, NULL, NULL);
if (!window) {
glfwTerminate();
return 0;
}
canvaW = width;
canvaH = height;
GAME_LOG_INFO("window create OK");
glfwMakeContextCurrent(window);
gladLoadGL();
GL_CALL(glViewport(0, 0, width, height));
glfwSetFramebufferSizeCallback(window, windowResizeCallback);
return 1;
}
void Hazel_WindowGetSize(int* w, int* h) {
glfwGetWindowSize(window, w, h);
}
void Hazel_WindowSetIcon(const char* filename) {
GLFWimage icon;
int channel;
icon.pixels = stbi_load(filename, &icon.width, &icon.height, &channel, 0);
if (!icon.pixels) {
ENGINE_LOG_ERROR("icon %s load failed", filename);
} else {
glfwSetWindowIcon(window, 1, &icon);
stbi_image_free(icon.pixels);
}
}

3
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
add_executable(main main.c)
target_link_libraries(main PUBLIC ${HAZEL_CORE_NAME})
target_precompile_headers(main REUSE_FROM ${HAZEL_CORE_NAME})

40
test/main.c Normal file
View File

@ -0,0 +1,40 @@
#include "hazel/hazel.h"
#include "hazel/renderer.h"
Hazel_Texture* texture = NULL;
void GameStart() {
texture = Hazel_LoadTexture("test/resources/player.png");
Hazel_TextureSetColor(texture, 0, 1, 0);
Hazel_TextureSetAlpha(texture, 0.3);
}
void GameLoop() {
Hazel_RenderSetClearColor(0.1, 0.1, 0.1, 1);
Hazel_RenderClear();
Hazel_RenderSetDrawColor(0.5, 0.1, 0.1, 1);
Hazel_RenderDrawLine(0, 0, 800, 600);
Hazel_RenderSetDrawColor(0, 0.8, 0.1, 1);
Hazel_RenderDrawRect(100, 100, 200, 100);
int w, h;
Hazel_TextureGetSize(texture, &w, &h);
Hazel_RenderDrawTexture(texture, 10, 0, 10, 10, 0, 0, w * 3, h * 3, FLIP_HORIZONTAL);
Hazel_RenderSetDrawColor(0, 0, 0.9, 1);
Hazel_RenderFillRect(100, 300, 200, 100);
}
void GameQuit() {
Hazel_DestroyTexture(texture);
}
int main() {
Hazel_Init("test", 800, 600);
Hazel_RegistGameFuncs(GameStart, GameLoop, GameQuit);
Hazel_Run();
Hazel_Quit();
return 0;
}

BIN
test/resources/player.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

BIN
test/resources/spike.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B