2026-01-12 01:54:35 +09:00
|
|
|
#include <GearSrc/Client.h>
|
2026-01-09 00:40:51 +09:00
|
|
|
|
2026-01-12 01:54:35 +09:00
|
|
|
#include <GearSrc/Log.h>
|
|
|
|
|
#include <GearSrc/GL.h>
|
|
|
|
|
#include <GearSrc/SkyBox.h>
|
|
|
|
|
#include <GearSrc/Math.h>
|
2026-01-13 04:28:36 +09:00
|
|
|
#include <GearSrc/Model.h>
|
2026-01-20 14:34:13 +09:00
|
|
|
#include <GearSrc/Version.h>
|
2026-01-27 14:36:27 +09:00
|
|
|
#include <GearSrc/SoundEngine.h>
|
2026-01-09 00:40:51 +09:00
|
|
|
|
2026-01-25 14:19:27 +09:00
|
|
|
#include <stb_ds.h>
|
|
|
|
|
|
2026-01-12 01:54:35 +09:00
|
|
|
GSClient GSClientCreate(GSEngine engine) {
|
|
|
|
|
GSClient client = malloc(sizeof(*client));
|
2026-01-25 06:31:19 +09:00
|
|
|
void* ptr[] = {
|
|
|
|
|
"game:/font/normal", /**/
|
|
|
|
|
"base:/font/normal", /**/
|
|
|
|
|
&client->font_normal, /**/
|
|
|
|
|
&client->glyph_normal_width, /**/
|
|
|
|
|
&client->glyph_normal_height, /**/
|
|
|
|
|
&client->font_normal_width, /**/
|
|
|
|
|
&client->font_normal_height, /**/
|
|
|
|
|
/**/
|
|
|
|
|
"game:/font/bold", /**/
|
|
|
|
|
"base:/font/bold", /**/
|
|
|
|
|
&client->font_bold, /**/
|
|
|
|
|
&client->glyph_bold_width, /**/
|
|
|
|
|
&client->glyph_bold_height, /**/
|
|
|
|
|
&client->font_bold_width, /**/
|
|
|
|
|
&client->font_bold_height /**/
|
|
|
|
|
};
|
|
|
|
|
int i;
|
2026-01-09 03:38:29 +09:00
|
|
|
|
|
|
|
|
memset(client, 0, sizeof(*client));
|
|
|
|
|
|
2026-01-09 06:12:57 +09:00
|
|
|
client->engine = engine;
|
|
|
|
|
|
2026-01-13 04:28:36 +09:00
|
|
|
client->camera[0] = 0;
|
2026-01-25 13:05:30 +09:00
|
|
|
client->camera[1] = 1.5;
|
2026-01-12 04:55:35 +09:00
|
|
|
client->camera[2] = 5;
|
2026-01-11 01:36:32 +09:00
|
|
|
|
|
|
|
|
client->look_at[0] = 0;
|
2026-01-25 01:56:36 +09:00
|
|
|
client->look_at[1] = 1;
|
2026-01-27 22:59:53 +09:00
|
|
|
client->look_at[2] = 0;
|
2026-01-11 01:36:32 +09:00
|
|
|
|
2026-01-12 04:41:17 +09:00
|
|
|
client->light0[0] = 2.5;
|
2026-01-11 17:43:03 +09:00
|
|
|
client->light0[1] = 5;
|
|
|
|
|
client->light0[2] = 5;
|
2026-01-25 01:56:36 +09:00
|
|
|
client->light0[3] = 0;
|
2026-01-11 01:36:32 +09:00
|
|
|
|
2026-01-20 14:07:56 +09:00
|
|
|
client->skybox_enabled = GSFalse;
|
|
|
|
|
|
2026-01-27 14:36:27 +09:00
|
|
|
if((client->sengine = GSSoundEngineCreate(client)) == NULL) {
|
|
|
|
|
GSLog(engine, GSLogError, "Failed to create sound engine");
|
2026-01-27 12:10:08 +09:00
|
|
|
GSClientDestroy(client);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 01:54:35 +09:00
|
|
|
client->gl = GSGLCreate(client);
|
2026-01-10 19:51:48 +09:00
|
|
|
|
2026-01-12 09:10:17 +09:00
|
|
|
client->skybox = GSSkyBoxTry(client, "default");
|
2026-01-12 01:03:18 +09:00
|
|
|
|
2026-01-25 06:31:19 +09:00
|
|
|
GSGLTextBold(client->gl, 0);
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < sizeof(ptr) / sizeof(ptr[0]); i += 7) {
|
|
|
|
|
if(GSGLTextureTryEx(client->gl, ptr[i + 2], ptr[i + 3], ptr[i + 4], ptr[i], 0)) {
|
|
|
|
|
} else if(GSGLTextureTryEx(client->gl, ptr[i + 2], ptr[i + 3], ptr[i + 4], ptr[i + 1], 0)) {
|
|
|
|
|
} else {
|
|
|
|
|
*((GLuint*)ptr[i + 2]) = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(*((GLuint*)ptr[i + 2]) > 0) {
|
|
|
|
|
*((int*)ptr[i + 5]) = GSMathClosestPOT(*((int*)ptr[i + 3]));
|
|
|
|
|
*((int*)ptr[i + 6]) = GSMathClosestPOT(*((int*)ptr[i + 4]));
|
|
|
|
|
*((int*)ptr[i + 3]) /= 16;
|
|
|
|
|
*((int*)ptr[i + 4]) /= 16;
|
|
|
|
|
}
|
2026-01-20 14:34:13 +09:00
|
|
|
}
|
|
|
|
|
|
2026-01-25 13:35:09 +09:00
|
|
|
GSLog(engine, GSLogInfo, "Created client");
|
2026-01-09 00:40:51 +09:00
|
|
|
|
2026-01-09 03:38:29 +09:00
|
|
|
return client;
|
2026-01-09 00:40:51 +09:00
|
|
|
}
|
|
|
|
|
|
2026-01-12 01:54:35 +09:00
|
|
|
void GSClientDestroy(GSClient client) {
|
2026-01-25 06:31:19 +09:00
|
|
|
if(client->font_normal != 0) GSGLTextureDelete(client->gl, client->font_normal);
|
|
|
|
|
if(client->font_bold != 0) GSGLTextureDelete(client->gl, client->font_bold);
|
2026-01-20 14:34:13 +09:00
|
|
|
|
2026-01-12 01:54:35 +09:00
|
|
|
GSGLDestroy(client->gl);
|
2026-01-10 19:51:48 +09:00
|
|
|
|
2026-01-27 14:36:27 +09:00
|
|
|
if(client->sengine != NULL) GSSoundEngineDestroy(client->sengine);
|
2026-01-27 12:10:08 +09:00
|
|
|
|
2026-01-25 13:35:09 +09:00
|
|
|
GSLog(client->engine, GSLogInfo, "Destroyed client");
|
2026-01-10 19:51:48 +09:00
|
|
|
|
2026-01-25 13:35:09 +09:00
|
|
|
free(client);
|
2026-01-09 00:40:51 +09:00
|
|
|
}
|
2026-01-09 03:38:29 +09:00
|
|
|
|
2026-01-28 13:25:31 +09:00
|
|
|
static GSVector4 white = {1, 1, 1, 1};
|
|
|
|
|
|
2026-01-12 01:54:35 +09:00
|
|
|
static void scene(GSClient client) {
|
2026-01-28 13:25:31 +09:00
|
|
|
GSGLSetColor(client->gl, white);
|
|
|
|
|
|
2026-01-20 14:07:56 +09:00
|
|
|
if(client->engine->param->render != NULL) client->engine->param->render(client->engine);
|
2026-01-28 13:25:31 +09:00
|
|
|
|
|
|
|
|
GSGLSetColor(client->gl, white);
|
2026-01-11 01:36:32 +09:00
|
|
|
}
|
|
|
|
|
|
2026-01-12 01:54:35 +09:00
|
|
|
void GSClientStep(GSClient client) {
|
2026-01-23 15:38:08 +09:00
|
|
|
int tw, th;
|
|
|
|
|
int tw2, th2;
|
|
|
|
|
int sw, sh;
|
|
|
|
|
char buf[512];
|
|
|
|
|
char buf2[512];
|
2026-01-20 14:34:13 +09:00
|
|
|
GSVersion ver;
|
2026-01-25 06:31:19 +09:00
|
|
|
GSVector4 yellow = {1, 1, 0, 1};
|
|
|
|
|
GSVector4 half = {0, 0, 0, 0.5};
|
2026-01-20 14:34:13 +09:00
|
|
|
GSVector2 sq[4];
|
2026-01-27 12:10:08 +09:00
|
|
|
int i, j, k, c, t;
|
2026-01-12 05:33:04 +09:00
|
|
|
|
2026-01-12 01:54:35 +09:00
|
|
|
GSGLClear(client->gl);
|
|
|
|
|
GSGLCameraSetup(client->gl);
|
|
|
|
|
GSGLSetLight(client->gl);
|
2026-01-11 01:36:32 +09:00
|
|
|
|
2026-01-25 06:31:19 +09:00
|
|
|
GSGLTextBold(client->gl, 0);
|
|
|
|
|
|
2026-01-12 01:54:35 +09:00
|
|
|
if(GSGLShadowBeforeMapping(client->gl)) {
|
2026-01-11 23:10:13 +09:00
|
|
|
scene(client);
|
2026-01-12 01:54:35 +09:00
|
|
|
GSGLShadowAfterMapping(client->gl);
|
2026-01-11 18:27:41 +09:00
|
|
|
}
|
2026-01-11 20:26:15 +09:00
|
|
|
|
2026-01-23 15:38:08 +09:00
|
|
|
if(client->skybox_enabled) {
|
2026-01-20 14:07:56 +09:00
|
|
|
if(client->skybox != NULL) GSSkyBoxDraw(client->skybox);
|
|
|
|
|
}
|
2026-01-11 23:10:13 +09:00
|
|
|
scene(client);
|
2026-01-12 01:54:35 +09:00
|
|
|
GSGLShadowEnd(client->gl);
|
2026-01-11 01:36:32 +09:00
|
|
|
|
2026-01-20 14:34:13 +09:00
|
|
|
GSVersionGet(&ver);
|
2026-01-23 15:38:08 +09:00
|
|
|
|
2026-01-25 06:31:19 +09:00
|
|
|
sprintf(buf, "Engine version %s", ver.string);
|
2026-01-23 15:38:08 +09:00
|
|
|
|
2026-01-20 14:34:13 +09:00
|
|
|
tw = GSGLTextWidth(client->gl, buf);
|
|
|
|
|
th = GSGLTextHeight(client->gl, buf);
|
|
|
|
|
|
|
|
|
|
sprintf(buf2, "%s", ver.copyright);
|
2026-01-23 15:38:08 +09:00
|
|
|
|
2026-01-20 14:34:13 +09:00
|
|
|
tw2 = GSGLTextWidth(client->gl, buf2);
|
|
|
|
|
th2 = GSGLTextHeight(client->gl, buf2);
|
|
|
|
|
|
|
|
|
|
sw = tw > tw2 ? tw : tw2;
|
|
|
|
|
sh = th + th2;
|
|
|
|
|
|
|
|
|
|
sq[0][0] = client->engine->width - sw, sq[0][1] = client->engine->height - sh;
|
2026-01-25 14:19:27 +09:00
|
|
|
sq[1][0] = sq[0][0], sq[1][1] = client->engine->height;
|
|
|
|
|
sq[2][0] = client->engine->width, sq[2][1] = sq[1][1];
|
|
|
|
|
sq[3][0] = sq[2][0], sq[3][1] = sq[0][1];
|
2026-01-20 14:34:13 +09:00
|
|
|
|
|
|
|
|
GSGLSetColor(client->gl, half);
|
|
|
|
|
GSGLBegin2D(client->gl);
|
|
|
|
|
GSGLPolygon2D(client->gl, 4, sq, NULL);
|
|
|
|
|
GSGLEnd2D(client->gl);
|
|
|
|
|
|
|
|
|
|
GSGLSetColor(client->gl, white);
|
|
|
|
|
GSGLText(client->gl, client->engine->width - tw, client->engine->height - th * 2, buf);
|
|
|
|
|
GSGLText(client->gl, client->engine->width - tw2, client->engine->height - th2, buf2);
|
2026-01-23 15:38:08 +09:00
|
|
|
|
2026-01-25 14:19:27 +09:00
|
|
|
for(k = 0; k < 2; k++) {
|
|
|
|
|
c = 0;
|
2026-01-27 12:10:08 +09:00
|
|
|
for(i = arrlen(client->engine->log) - 1, j = 0; i >= 0 && j < 5; i--, j++) {
|
2026-01-25 14:19:27 +09:00
|
|
|
if(client->engine->param->get_tick != NULL) {
|
|
|
|
|
if((client->engine->param->get_tick() - client->engine->log[i].tick) > 3000) continue;
|
|
|
|
|
}
|
2026-01-11 01:36:32 +09:00
|
|
|
|
2026-01-25 14:19:27 +09:00
|
|
|
if(k == 1) {
|
2026-01-27 12:10:08 +09:00
|
|
|
GSNumber y = (t - c - 1) * GSGLTextHeight(client->gl, "M");
|
2026-01-25 14:19:27 +09:00
|
|
|
GSNumber w = 0;
|
|
|
|
|
char str[6];
|
|
|
|
|
int level = client->engine->log[i].level;
|
|
|
|
|
GSVector4 col = {0, 0, 0, 1};
|
|
|
|
|
|
|
|
|
|
str[0] = 0;
|
|
|
|
|
|
|
|
|
|
if(level == GSLogInfo) {
|
|
|
|
|
strcpy(str, "INFO");
|
|
|
|
|
|
|
|
|
|
col[0] = col[1] = col[2] = 1;
|
|
|
|
|
} else if(level == GSLogWarn) {
|
|
|
|
|
strcpy(str, "WARN");
|
|
|
|
|
|
|
|
|
|
col[0] = col[2] = 1;
|
|
|
|
|
} else if(level == GSLogError) {
|
|
|
|
|
strcpy(str, "ERROR");
|
|
|
|
|
|
|
|
|
|
col[0] = 1;
|
|
|
|
|
} else if(level == GSLogDebug) {
|
|
|
|
|
strcpy(str, "DEBUG");
|
|
|
|
|
|
|
|
|
|
col[2] = 1;
|
|
|
|
|
}
|
|
|
|
|
GSGLSetColor(client->gl, col);
|
2026-01-25 01:56:36 +09:00
|
|
|
|
2026-01-25 14:19:27 +09:00
|
|
|
GSGLTextBold(client->gl, 1);
|
|
|
|
|
GSGLText(client->gl, (5 - strlen(str)) * GSGLTextWidth(client->gl, "M") / 2, y, str);
|
|
|
|
|
GSGLTextBold(client->gl, 0);
|
2026-01-25 01:56:36 +09:00
|
|
|
|
2026-01-25 14:19:27 +09:00
|
|
|
GSGLSetColor(client->gl, white);
|
|
|
|
|
GSGLText(client->gl, 0, y, " |");
|
|
|
|
|
GSGLText(client->gl, GSGLTextWidth(client->gl, "M") * 6, y, client->engine->log[i].log);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c++;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-27 12:10:08 +09:00
|
|
|
t = c;
|
|
|
|
|
|
2026-01-25 14:19:27 +09:00
|
|
|
if(k == 0) {
|
|
|
|
|
sq[0][0] = 0, sq[0][1] = 0;
|
|
|
|
|
sq[1][0] = 0, sq[1][1] = c * GSGLTextHeight(client->gl, "M");
|
|
|
|
|
sq[2][0] = client->engine->width, sq[2][1] = sq[1][1];
|
|
|
|
|
sq[3][0] = sq[2][0], sq[3][1] = 0;
|
|
|
|
|
|
|
|
|
|
GSGLSetColor(client->gl, half);
|
|
|
|
|
GSGLBegin2D(client->gl);
|
|
|
|
|
GSGLPolygon2D(client->gl, 4, sq, NULL);
|
|
|
|
|
GSGLEnd2D(client->gl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sprintf(buf, "%.1f FPS", client->engine->tps_sampled);
|
|
|
|
|
sprintf(buf2, "%s%s", client->engine->tps_sampled < 10 ? " " : "", buf);
|
|
|
|
|
|
|
|
|
|
tw = GSGLTextWidth(client->gl, buf2);
|
|
|
|
|
th = GSGLTextHeight(client->gl, buf2);
|
|
|
|
|
|
|
|
|
|
sq[0][0] = client->engine->width - tw, sq[0][1] = 0;
|
|
|
|
|
sq[1][0] = sq[0][0], sq[1][1] = th;
|
|
|
|
|
sq[2][0] = client->engine->width, sq[2][1] = sq[1][1];
|
|
|
|
|
sq[3][0] = sq[2][0], sq[3][1] = 0;
|
|
|
|
|
|
|
|
|
|
GSGLSetColor(client->gl, half);
|
|
|
|
|
GSGLBegin2D(client->gl);
|
|
|
|
|
GSGLPolygon2D(client->gl, 4, sq, NULL);
|
|
|
|
|
GSGLEnd2D(client->gl);
|
|
|
|
|
|
|
|
|
|
GSGLSetColor(client->gl, yellow);
|
|
|
|
|
GSGLTextBold(client->gl, 1);
|
|
|
|
|
GSGLText(client->gl, client->engine->width - tw, 0, buf2);
|
|
|
|
|
GSGLTextBold(client->gl, 0);
|
|
|
|
|
|
|
|
|
|
client->engine->param->gl_swapbuffer();
|
|
|
|
|
|
|
|
|
|
if(client->engine->param->after_render != NULL) client->engine->param->after_render(client->engine);
|
2026-01-20 14:07:56 +09:00
|
|
|
}
|
2026-01-12 04:55:35 +09:00
|
|
|
|
2026-01-23 15:38:08 +09:00
|
|
|
GSGL GSClientGetGL(GSClient client) {
|
2026-01-20 14:07:56 +09:00
|
|
|
return client->gl;
|
|
|
|
|
}
|
2026-01-11 01:36:32 +09:00
|
|
|
|
2026-01-27 14:36:27 +09:00
|
|
|
GSSoundEngine GSClientGetSoundEngine(GSClient client) {
|
|
|
|
|
return client->sengine;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-27 18:52:13 +09:00
|
|
|
void GSClientSetSkybox(GSClient client, GSBool toggle) {
|
2026-01-20 14:07:56 +09:00
|
|
|
client->skybox_enabled = toggle;
|
2026-01-09 03:38:29 +09:00
|
|
|
}
|