ADD: WebASM port (no sound/no network)

This commit is contained in:
Kolyah35
2026-03-19 02:26:34 +03:00
parent 4769d4ae72
commit e9914e3fbd
13 changed files with 408 additions and 119 deletions

View File

@@ -31,7 +31,7 @@ public:
{
}
BinaryBlob readAssetFile(const std::string& filename) {
BinaryBlob readAssetFile(const std::string& filename) override {
FILE* fp = fopen(("data/" + filename).c_str(), "r");
if (!fp)
return BinaryBlob();
@@ -48,7 +48,7 @@ public:
return blob;
}
void saveScreenshot(const std::string& filename, int glWidth, int glHeight) {
void saveScreenshot(const std::string& filename, int glWidth, int glHeight) override {
//@todo
}
@@ -56,7 +56,7 @@ public:
return (p & 0xff00ff00) | ((p >> 16) & 0xff) | ((p << 16) & 0xff0000);
}
TextureData loadTexture(const std::string& filename_, bool textureFolder)
TextureData loadTexture(const std::string& filename_, bool textureFolder) override
{
// Support fetching PNG textures via HTTP/HTTPS (for skins, etc)
if (Util::startsWith(filename_, "http://") || Util::startsWith(filename_, "https://")) {
@@ -132,10 +132,10 @@ public:
return std::string(mbstr);
}
virtual int getScreenWidth() { return 854; };
virtual int getScreenHeight() { return 480; };
virtual int getScreenWidth() override { return 854; };
virtual int getScreenHeight() override { return 480; };
virtual float getPixelsPerMillimeter();
virtual float getPixelsPerMillimeter() override;
virtual bool supportsTouchscreen() override { return true; }
@@ -148,6 +148,8 @@ public:
#endif
}
GLFWwindow* window;
private:
};
#endif /*APPPLATFORM_GLFW_H__*/

View File

@@ -245,8 +245,9 @@ void NinecraftApp::initGLStates()
glCullFace(GL_BACK);
glEnable2(GL_TEXTURE_2D);
#ifndef _EMSCRIPTEN_
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
#endif
// Both updates isPowerVR flag in java and returns if the graphics chip is PowerVR SGX or not
_powerVr = platform()->isPowerVR();
#ifdef __APPLE__

View File

@@ -37,6 +37,8 @@ void CreditsScreen::init() {
_lines.push_back("mschiller890");
_lines.push_back("InviseDivine");
_lines.push_back("Kolyah35");
_lines.push_back("karson");
_lines.push_back("deepfriedwaffles");
_lines.push_back("");
// avoid color tags around the URL so it isn't mangled by the parser please
_lines.push_back("Join our Discord server: https://discord.gg/c58YesBxve");

View File

@@ -86,21 +86,21 @@ public:
SelectWorldScreen();
virtual ~SelectWorldScreen();
virtual void init();
virtual void setupPositions();
virtual void init() override;
virtual void setupPositions() override;
virtual void tick();
virtual void render(int xm, int ym, float a);
virtual void tick() override;
virtual void render(int xm, int ym, float a) override;
virtual bool isIndexValid(int index);
virtual bool handleBackEvent(bool isDown);
virtual void buttonClicked(Button* button);
virtual void keyPressed(int eventKey);
virtual bool handleBackEvent(bool isDown) override;
virtual void buttonClicked(Button* button) override;
virtual void keyPressed(int eventKey) override;
// support for mouse wheel when desktop code uses touch variant
virtual void mouseWheel(int dx, int dy, int xm, int ym) override;
bool isInGameScreen();
bool isInGameScreen() override;
private:
void loadLevelSource();
std::string getUniqueLevelName(const std::string& level);

View File

@@ -79,6 +79,9 @@ RenderChunk Tesselator::end( bool useMine, int bufferId )
const int o_vertices = vertices;
if (vertices > 0) {
if (p <= 0 || p > maxVertices) { clear(); return RenderChunk(); }
int bytes = p * sizeof(VERTEX);
if (bytes <= 0) return RenderChunk();
if (++vboId >= vboCounts)
vboId = 0;
@@ -92,11 +95,11 @@ RenderChunk Tesselator::end( bool useMine, int bufferId )
bufferId = vboIds[vboId];
#endif
int access = GL_STATIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW;
int bytes = p * sizeof(VERTEX);
glBindBuffer2(GL_ARRAY_BUFFER, bufferId);
glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW
totalSize += bytes;
#ifndef USE_VBO
// 0 1 2 3 4 5 6 7
// x y z u v c
@@ -264,6 +267,7 @@ void Tesselator::vertex( float x, float y, float z )
for (int i = 0; i < 2; i++) {
const int offs = 3 - i;
if (p - offs < 0 || p >= maxVertices) { clear(); return; }
VERTEX& src = _varray[p - offs];
VERTEX& dst = _varray[p];
@@ -287,6 +291,7 @@ void Tesselator::vertex( float x, float y, float z )
}
}
if (p < 0 || p >= maxVertices) { clear(); return; }
VERTEX& vertex = _varray[p];
if (hasTexture) {
@@ -377,13 +382,15 @@ void Tesselator::draw()
tesselating = false;
if (vertices > 0) {
if (p <= 0 || p > maxVertices) { clear(); return; }
int bytes = p * sizeof(VERTEX);
if (bytes <= 0) { clear(); return; }
if (++vboId >= vboCounts)
vboId = 0;
int bufferId = vboIds[vboId];
int access = GL_DYNAMIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW;
int bytes = p * sizeof(VERTEX);
glBindBuffer2(GL_ARRAY_BUFFER, bufferId);
glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW

View File

@@ -47,9 +47,13 @@ void glInit()
}
void anGenBuffers(GLsizei n, GLuint* buffers) {
static GLuint k = 1;
for (int i = 0; i < n; ++i)
buffers[i] = ++k;
#ifdef __EMSCRIPTEN__
glGenBuffers(n, buffers);
#else
static GLuint k = 1;
for (int i = 0; i < n; ++i)
buffers[i] = ++k;
#endif
}
#ifdef USE_VBO

View File

@@ -10,13 +10,13 @@
#endif
// Other systems might run it, if they #define OPENGL_ES
#if defined(OPENGL_ES) // || defined(ANDROID)
// #if defined(OPENGL_ES) // || defined(ANDROID)
#define USE_VBO
#define GL_QUADS 0x0007
#if defined(__APPLE__)
#import <OpenGLES/ES1/gl.height>
#import <OpenGLES/ES1/glext.height>
#elif defined(ANDROID)
#elif defined(ANDROID) || defined(__EMSCRIPTEN__)
#include <GLES/gl.h>
#include <GLES/glext.h>
#else
@@ -28,18 +28,18 @@
#define glClearDepthf(x) glClearDepth(x)
#define glDepthRangef(a,b) glDepthRange(a,b)
#endif
#else
// Uglyness to fix redeclaration issues
#ifdef WIN32
#include <WinSock2.h>
#include <Windows.h>
#endif
#include <gl/glew.h>
#include <gl/GL.h>
// #else
// // Uglyness to fix redeclaration issues
// #ifdef WIN32
// #include <WinSock2.h>
// #include <Windows.h>
// #endif
// #include <gl/glew.h>
// #include <gl/GL.h>
#define glFogx(a,b) glFogi(a,b)
#define glOrthof(a,b,c,d,e,f) glOrtho(a,b,c,d,e,f)
#endif
// #define glFogx(a,b) glFogi(a,b)
// #define glOrthof(a,b,c,d,e,f) glOrtho(a,b,c,d,e,f)
// #endif
#define GLERRDEBUG 1

View File

@@ -2,9 +2,9 @@
#define MAIN_GLFW_H__
#include "App.h"
#include "GLFW/glfw3.h"
#include "client/renderer/entity/PlayerRenderer.h"
#include "client/renderer/gles.h"
#include "SharedConstants.h"
#include "GLFW/glfw3.h"
#include <cstdio>
#include <chrono>
@@ -12,9 +12,10 @@
#include "platform/input/Keyboard.h"
#include "platform/input/Mouse.h"
#include "platform/input/Multitouch.h"
#include "util/Mth.h"
#include "AppPlatform_glfw.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
static App* g_app = 0;
int transformKey(int glfwkey) {
@@ -112,12 +113,39 @@ void error_callback(int error, const char* desc) {
printf("Error: %s\n", desc);
}
void loop() {
using clock = std::chrono::steady_clock;
auto frameStart = clock::now();
g_app->update();
glfwSwapBuffers(((AppPlatform_glfw*)g_app->platform())->window);
glfwPollEvents();
glfwSwapInterval(((MAIN_CLASS*)g_app)->options.getBooleanValue(OPTIONS_VSYNC) ? 1 : 0);
if(((MAIN_CLASS*)g_app)->options.getBooleanValue(OPTIONS_LIMIT_FRAMERATE)) {
auto frameEnd = clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(frameEnd - frameStart);
auto target = std::chrono::microseconds(33333); // ~30 fps
if(elapsed < target)
std::this_thread::sleep_for(target - elapsed);
}
}
int main(void) {
AppContext appContext;
#ifndef STANDALONE_SERVER
// Platform init.
appContext.platform = new AppPlatform_glfw();
#if defined(DEBUG) && defined(__EMSCRIPTEN__)
EM_ASM({
console.log(FS.readdir("/"));
console.log(FS.readdir("/data"));
console.log(FS.readdir("/data/images"));
});
#endif
glfwSetErrorCallback(error_callback);
@@ -126,26 +154,36 @@ int main(void) {
}
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API);
#ifndef __EMSCRIPTEN__
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#else
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
#endif
GLFWwindow* window = glfwCreateWindow(appContext.platform->getScreenWidth(), appContext.platform->getScreenHeight(), "main", NULL, NULL);
AppPlatform_glfw* platform = (AppPlatform_glfw*)appContext.platform;
platform->window = glfwCreateWindow(appContext.platform->getScreenWidth(), appContext.platform->getScreenHeight(), "main", NULL, NULL);
if (window == NULL) {
if (platform->window == NULL) {
return 1;
}
glfwSetKeyCallback(window, key_callback);
glfwSetCharCallback(window, character_callback);
glfwSetCursorPosCallback(window, cursor_position_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetScrollCallback(window, scroll_callback);
glfwSetWindowSizeCallback(window, window_size_callback);
glfwSetKeyCallback(platform->window, key_callback);
glfwSetCharCallback(platform->window, character_callback);
glfwSetCursorPosCallback(platform->window, cursor_position_callback);
glfwSetMouseButtonCallback(platform->window, mouse_button_callback);
glfwSetScrollCallback(platform->window, scroll_callback);
glfwSetWindowSizeCallback(platform->window, window_size_callback);
glfwMakeContextCurrent(window);
glfwMakeContextCurrent(platform->window);
#ifndef __EMSCRIPTEN__
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
glfwSwapInterval(0);
#endif
#endif
App* app = new MAIN_CLASS();
@@ -156,25 +194,14 @@ int main(void) {
g_app->init(appContext);
g_app->setSize(appContext.platform->getScreenWidth(), appContext.platform->getScreenHeight());
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(loop, 0, 1);
#else
// Main event loop
using clock = std::chrono::steady_clock;
while(!glfwWindowShouldClose(window) && !app->wantToQuit()) {
auto frameStart = clock::now();
app->update();
glfwSwapBuffers(window);
glfwPollEvents();
glfwSwapInterval(((MAIN_CLASS*)app)->options.getBooleanValue(OPTIONS_VSYNC) ? 1 : 0);
if(((MAIN_CLASS*)app)->options.getBooleanValue(OPTIONS_LIMIT_FRAMERATE)) {
auto frameEnd = clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(frameEnd - frameStart);
auto target = std::chrono::microseconds(33333); // ~30 fps
if(elapsed < target)
std::this_thread::sleep_for(target - elapsed);
}
while(!glfwWindowShouldClose(platform->window) && !app->wantToQuit()) {
loop();
}
#endif
delete app;
@@ -184,7 +211,7 @@ int main(void) {
#ifndef STANDALONE_SERVER
// Exit.
glfwDestroyWindow(window);
glfwDestroyWindow(platform->window);
glfwTerminate();
#endif

View File

@@ -25,7 +25,7 @@
&m_threadID // pointer to receive thread ID
);
#endif
#if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX)
#if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) || defined(__EMSCRIPTEN__)
mp_threadFunc = (pthread_fn)threadFunc;
pthread_attr_init(&m_attributes);

View File

@@ -13,7 +13,7 @@
typedef void *( * pthread_fn )( void * );
#if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX)
#if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) || defined(__EMSCRIPTEN__)
#include <pthread.h>
#include <unistd.h>
@@ -38,7 +38,7 @@ typedef void *( * pthread_fn )( void * );
DWORD m_threadID;
HANDLE m_threadHandle;
#endif
#if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX)
#if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) || defined(__EMSCRIPTEN__)
pthread_fn mp_threadFunc;
pthread_t m_thread;
pthread_attr_t m_attributes;