mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-09 06:36:59 +02:00
WebGL platform
This commit is contained in:
@@ -238,7 +238,7 @@ struct Controller {
|
||||
|
||||
void *p = &level->soundData[c];
|
||||
|
||||
PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
|
||||
// PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
16
src/core.h
16
src/core.h
@@ -2,9 +2,17 @@
|
||||
#define H_CORE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <gl/GL.h>
|
||||
#include <gl/glext.h>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <gl/GL.h>
|
||||
#include <gl/glext.h>
|
||||
#elif __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#include <html5.h>
|
||||
#include <GLES3/gl3.h>
|
||||
#include <GLES3/gl2ext.h>
|
||||
#define MOBILE
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "input.h"
|
||||
@@ -72,6 +80,7 @@ enum BlendMode { bmNone, bmAlpha, bmAdd, bmMultiply, bmScreen };
|
||||
namespace Core {
|
||||
|
||||
void init() {
|
||||
#ifdef WIN32
|
||||
GetProcOGL(glActiveTexture);
|
||||
|
||||
GetProcOGL(glCreateProgram);
|
||||
@@ -99,6 +108,7 @@ namespace Core {
|
||||
GetProcOGL(glDeleteBuffers);
|
||||
GetProcOGL(glBindBuffer);
|
||||
GetProcOGL(glBufferData);
|
||||
#endif
|
||||
}
|
||||
|
||||
void free() {
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
//#define TR1_DEMO
|
||||
#define TR1_DEMO
|
||||
|
||||
namespace TR {
|
||||
#define DATA_PORTAL 0x01
|
||||
|
@@ -11,8 +11,8 @@ namespace Game {
|
||||
Level *level;
|
||||
|
||||
void init() {
|
||||
Core::init();
|
||||
level = new Level("data\\GYM.PHD");
|
||||
Core::init();
|
||||
level = new Level("data\\LEVEL2_DEMO.PHD");
|
||||
}
|
||||
|
||||
void free() {
|
||||
|
@@ -59,6 +59,7 @@ namespace Input {
|
||||
case ikMouseM : mouse.start.M = mouse.pos; break;
|
||||
case ikTouchA : touch.start.A = touch.A; break;
|
||||
case ikTouchB : touch.start.B = touch.B; break;
|
||||
default : ;
|
||||
}
|
||||
|
||||
down[key] = value;
|
||||
@@ -76,6 +77,7 @@ namespace Input {
|
||||
case ikJoyDP : joy.DP = pos.x; break;
|
||||
case ikTouchA : touch.A = pos; break;
|
||||
case ikTouchB : touch.B = pos; break;
|
||||
default : ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
25
src/level.h
25
src/level.h
@@ -6,7 +6,10 @@
|
||||
#include "format.h"
|
||||
#include "controller.h"
|
||||
#include "camera.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include "debug.h"
|
||||
#endif
|
||||
|
||||
const char SHADER[] =
|
||||
#include "shader.glsl"
|
||||
@@ -187,7 +190,7 @@ struct Level {
|
||||
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z };
|
||||
vertices[vCount].color = { a, a, a, 255 };
|
||||
vertices[vCount].normal = { 0, 0, 0, 0x7FFF };
|
||||
vertices[vCount].texCoord = { ((tx + t.vertices[k].Xpixel) << 5) + 16, ((ty + t.vertices[k].Ypixel) << 5) + 16};
|
||||
vertices[vCount].texCoord = { (int16)((tx + (int)t.vertices[k].Xpixel) << 5) + 16, (int16)((ty + (int)t.vertices[k].Ypixel) << 5) + 16};
|
||||
vCount++;
|
||||
}
|
||||
}
|
||||
@@ -215,7 +218,7 @@ struct Level {
|
||||
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z };
|
||||
vertices[vCount].color = { a, a, a, 255 };
|
||||
vertices[vCount].normal = { 0, 0, 0, 0x7FFF };
|
||||
vertices[vCount].texCoord = { ((tx + t.vertices[k].Xpixel) << 5) + 16, ((ty + t.vertices[k].Ypixel) << 5) + 16};
|
||||
vertices[vCount].texCoord = { (int16)((tx + (int)t.vertices[k].Xpixel) << 5) + 16, (int16)((ty + (int)t.vertices[k].Ypixel) << 5) + 16};
|
||||
vCount++;
|
||||
}
|
||||
}
|
||||
@@ -284,7 +287,7 @@ struct Level {
|
||||
vertices[vCount].normal = { 0, 0, 0, 255 };
|
||||
vertices[vCount].color = { a, a, a, 255 };
|
||||
}
|
||||
vertices[vCount].texCoord = { ((tx + t.vertices[k].Xpixel) << 5) + 16, ((ty + t.vertices[k].Ypixel) << 5) + 16};
|
||||
vertices[vCount].texCoord = { (int16)((tx + (int)t.vertices[k].Xpixel) << 5) + 16, (int16)((ty + (int)t.vertices[k].Ypixel) << 5) + 16};
|
||||
vCount++;
|
||||
}
|
||||
}
|
||||
@@ -320,7 +323,7 @@ struct Level {
|
||||
vertices[vCount].normal = { 0, 0, 0, 255 };
|
||||
vertices[vCount].color = { a, a, a, 255 };
|
||||
}
|
||||
vertices[vCount].texCoord = { ((tx + t.vertices[k].Xpixel) << 5) + 16, ((ty + t.vertices[k].Ypixel) << 5) + 16};
|
||||
vertices[vCount].texCoord = { ((tx + t.vertices[k].Xpixel) << 5) + 16, ((ty + t.vertices[k].Ypixel) << 5) + 16 };
|
||||
vCount++;
|
||||
}
|
||||
}
|
||||
@@ -488,6 +491,7 @@ struct Level {
|
||||
p[3] = right * sprite.r + up * sprite.t;
|
||||
|
||||
// bindTexture(sprite.tile);
|
||||
/*
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(u0, v1);
|
||||
glVertex3fv((GLfloat*)&p[0]);
|
||||
@@ -498,11 +502,13 @@ struct Level {
|
||||
glTexCoord2f(u0, v0);
|
||||
glVertex3fv((GLfloat*)&p[3]);
|
||||
glEnd();
|
||||
*/
|
||||
}
|
||||
|
||||
void renderSprite(const TR::Room &room, const TR::Room::Data::Sprite &sprite) {
|
||||
auto &v = room.data.vertices[sprite.vertex];
|
||||
float a = 1.0f - v.lighting / (float)0x1FFF;
|
||||
/*
|
||||
glColor3f(a, a, a);
|
||||
|
||||
glPushMatrix();
|
||||
@@ -511,6 +517,7 @@ struct Level {
|
||||
renderSprite(level.spriteTextures[sprite.texture]);
|
||||
|
||||
glPopMatrix();
|
||||
*/
|
||||
}
|
||||
|
||||
vec3 getAngle(TR::AnimFrame *frame, int index) {
|
||||
@@ -702,6 +709,7 @@ struct Level {
|
||||
Core::mModel = m;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
void debugPortals() {
|
||||
Core::setBlending(bmAdd);
|
||||
glColor3f(0, 0.25f, 0.25f);
|
||||
@@ -898,7 +906,7 @@ struct Level {
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
void debugEntity() {
|
||||
Core::setCulling(cfNone);
|
||||
@@ -996,11 +1004,8 @@ struct Level {
|
||||
shader->setParam(uViewProj, Core::mViewProj);
|
||||
shader->setParam(uModel, Core::mModel);
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.9f);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
Core::setCulling(cfFront);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
Core::mModel.identity();
|
||||
|
||||
|
@@ -29,7 +29,10 @@ varying vec4 vColor;
|
||||
uniform vec4 uLightColor;
|
||||
|
||||
void main() {
|
||||
vec4 color = texture2D(sDiffuse, vTexCoord) * vColor * uColor;
|
||||
vec4 color = texture2D(sDiffuse, vTexCoord);
|
||||
if (color.w < 0.9)
|
||||
discard;
|
||||
color *= vColor * uColor;
|
||||
// #ifdef LIGHTING
|
||||
color.xyz = pow(color.xyz, vec3(2.2));
|
||||
float lum = dot(normalize(vNormal.xyz), normalize(vLightVec));
|
||||
|
26
src/utils.h
26
src/utils.h
@@ -131,23 +131,23 @@ struct quat {
|
||||
w = cosf(angle);
|
||||
}
|
||||
|
||||
quat quat::operator - () const {
|
||||
quat operator - () const {
|
||||
return quat(-x, -y, -z, -w);
|
||||
}
|
||||
|
||||
quat quat::operator + (const quat &q) const {
|
||||
quat operator + (const quat &q) const {
|
||||
return quat(x + q.x, y + q.y, z + q.z, w + q.w);
|
||||
}
|
||||
|
||||
quat quat::operator - (const quat &q) const {
|
||||
quat operator - (const quat &q) const {
|
||||
return quat(x - q.x, y - q.y, z - q.z, w - q.w);
|
||||
}
|
||||
|
||||
quat quat::operator * (const float s) const {
|
||||
quat operator * (const float s) const {
|
||||
return quat(x * s, y * s, z * s, w * s);
|
||||
}
|
||||
|
||||
quat quat::operator * (const quat &q) const {
|
||||
quat operator * (const quat &q) const {
|
||||
return quat(w * q.x + x * q.w + y * q.z - z * q.y,
|
||||
w * q.y + y * q.w + z * q.x - x * q.z,
|
||||
w * q.z + z * q.w + x * q.y - y * q.x,
|
||||
@@ -166,19 +166,19 @@ struct quat {
|
||||
return sqrtf(length2());
|
||||
}
|
||||
|
||||
void quat::normalize() {
|
||||
void normalize() {
|
||||
*this = normal();
|
||||
}
|
||||
|
||||
quat quat::normal() const {
|
||||
quat normal() const {
|
||||
return *this * (1.0f / length());
|
||||
}
|
||||
|
||||
quat quat::conjugate() const {
|
||||
quat conjugate() const {
|
||||
return quat(-x, -y, -z, w);
|
||||
}
|
||||
|
||||
quat quat::inverse() const {
|
||||
quat inverse() const {
|
||||
return conjugate() * (1.0f / length2());
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ struct mat4 {
|
||||
return r;
|
||||
}
|
||||
|
||||
quat mat4::getRot() const {
|
||||
quat getRot() const {
|
||||
float t, s;
|
||||
t = 1.0f + e00 + e11 + e22;
|
||||
if (t > EPS) {
|
||||
@@ -402,7 +402,7 @@ struct mat4 {
|
||||
}
|
||||
}
|
||||
|
||||
void mat4::setRot(const quat &rot) {
|
||||
void setRot(const quat &rot) {
|
||||
float sx = rot.x * rot.x,
|
||||
sy = rot.y * rot.y,
|
||||
sz = rot.z * rot.z,
|
||||
@@ -430,11 +430,11 @@ struct mat4 {
|
||||
e12 = (t1 - t2) * inv;
|
||||
}
|
||||
|
||||
vec3 mat4::getPos() const {
|
||||
vec3 getPos() const {
|
||||
return offset.xyz;
|
||||
}
|
||||
|
||||
void mat4::setPos(const vec3 &pos) {
|
||||
void setPos(const vec3 &pos) {
|
||||
offset.xyz = pos;
|
||||
}
|
||||
};
|
||||
|
2
src/web/build.bat
Normal file
2
src/web/build.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
set SRC=main.cpp
|
||||
em++ %SRC% -O2 --llvm-opts 2 --closure 1 -std=c++11 -o OpenLara.js --preload-file ./../../bin/data/LEVEL2_DEMO.PHD -I..\
|
77
src/web/index.html
Normal file
77
src/web/index.html
Normal file
@@ -0,0 +1,77 @@
|
||||
<html>
|
||||
<head><title>OpenLara</title><head>
|
||||
<body>
|
||||
<span id="status">Starting...</span>
|
||||
<span><input type="button" value="fullscreen" onclick="Module.requestFullScreen(false, true)"><br><br>
|
||||
<canvas id="canvas" width="160" height="120" oncontextmenu="event.preventDefault()"></canvas><br>
|
||||
<span id="info"></span>
|
||||
|
||||
<script type='text/javascript'>
|
||||
var statusElement = document.getElementById('status');
|
||||
var canvasElement = document.getElementById('canvas');
|
||||
|
||||
var Module = {
|
||||
preRun: [],
|
||||
postRun: [],
|
||||
print: (function() {
|
||||
return function(text) {
|
||||
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.log(text);
|
||||
};
|
||||
})(),
|
||||
printErr: function(text) {
|
||||
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||
if (0) {
|
||||
dump(text + '\n');
|
||||
} else {
|
||||
console.error(text);
|
||||
}
|
||||
},
|
||||
canvas: (function() {
|
||||
canvasElement.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
|
||||
return canvasElement;
|
||||
})(),
|
||||
setStatus: function(text) {
|
||||
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
|
||||
if (text === Module.setStatus.text) return;
|
||||
statusElement.innerHTML = text;
|
||||
},
|
||||
totalDependencies: 0,
|
||||
monitorRunDependencies: function(left) {
|
||||
this.totalDependencies = Math.max(this.totalDependencies, left);
|
||||
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
|
||||
}
|
||||
};
|
||||
|
||||
var gl = canvasElement.getContext("webgl") || canvasElement.getContext("experimental-webgl");
|
||||
|
||||
Module.setStatus('Downloading...');
|
||||
window.onerror = function(event) {
|
||||
Module.setStatus('Exception thrown, see JavaScript console');
|
||||
//spinnerElement.style.display = 'none';
|
||||
document.getElementById('info').innerHTML = event;
|
||||
Module.setStatus = function(text) {
|
||||
if (text) Module.printErr('[post-exception status] ' + text);
|
||||
};
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
(function() {
|
||||
var memoryInitializer = 'OpenLara.js.mem';
|
||||
if (typeof Module['locateFile'] === 'function') {
|
||||
memoryInitializer = Module['locateFile'](memoryInitializer);
|
||||
} else if (Module['memoryInitializerPrefixURL']) {
|
||||
memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer;
|
||||
}
|
||||
var xhr = Module['memoryInitializerRequest'] = new XMLHttpRequest();
|
||||
xhr.open('GET', memoryInitializer, true);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.send(null);
|
||||
})();
|
||||
|
||||
var script = document.createElement('script');
|
||||
script.src = "OpenLara.js";
|
||||
document.body.appendChild(script);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
190
src/web/main.cpp
Normal file
190
src/web/main.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#include <stdio.h>
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include "game.h"
|
||||
|
||||
int lastTime, fpsTime, FPS;
|
||||
EGLDisplay display;
|
||||
EGLSurface surface;
|
||||
EGLContext context;
|
||||
|
||||
int getTime() {
|
||||
return (int)emscripten_get_now();
|
||||
}
|
||||
|
||||
void main_loop() {
|
||||
int time = getTime();
|
||||
|
||||
if (time - lastTime <= 0)
|
||||
return;
|
||||
|
||||
Core::deltaTime = (time - lastTime) * 0.001f;
|
||||
lastTime = time;
|
||||
|
||||
if (time > fpsTime) {
|
||||
fpsTime = time + 1000;
|
||||
LOG("FPS: %d\n", FPS);
|
||||
FPS = 0;
|
||||
}
|
||||
|
||||
Game::update();
|
||||
Game::render();
|
||||
eglSwapBuffers(display, surface);
|
||||
|
||||
FPS++;
|
||||
}
|
||||
|
||||
bool initGL() {
|
||||
EGLint vMajor, vMinor, cfgCount;
|
||||
EGLConfig cfg;
|
||||
|
||||
EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
|
||||
EGLint attribList[] = {
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 8,
|
||||
EGL_STENCIL_SIZE, EGL_DONT_CARE,
|
||||
EGL_SAMPLE_BUFFERS, EGL_DONT_CARE,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
display = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
|
||||
eglInitialize(display, &vMajor, &vMinor);
|
||||
eglGetConfigs(display, NULL, 0, &cfgCount);
|
||||
eglChooseConfig(display, attribList, &cfg, 1, &cfgCount);
|
||||
surface = eglCreateWindowSurface(display, cfg, NULL, NULL);
|
||||
context = eglCreateContext(display, cfg, EGL_NO_CONTEXT, contextAttribs);
|
||||
eglMakeCurrent(display, surface, surface, context);
|
||||
return true;
|
||||
}
|
||||
|
||||
void freeGL() {
|
||||
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
eglDestroyContext(display, context);
|
||||
eglDestroySurface(display, surface);
|
||||
eglTerminate(display);
|
||||
}
|
||||
|
||||
InputKey keyToInputKey(int code) {
|
||||
int codes[] = {
|
||||
0x25, 0x27, 0x26, 0x28, 0x20, 0x0D, 0x1B, 0x10, 0x11, 0x12,
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(codes) / sizeof(codes[0]); i++)
|
||||
if (codes[i] == code)
|
||||
return (InputKey)(ikLeft + i);
|
||||
return ikNone;
|
||||
}
|
||||
|
||||
EM_BOOL keyCallback(int eventType, const EmscriptenKeyboardEvent *e, void *userData) {
|
||||
switch(eventType) {
|
||||
case EMSCRIPTEN_EVENT_KEYDOWN:
|
||||
case EMSCRIPTEN_EVENT_KEYUP:
|
||||
Input::setDown(keyToInputKey(e->keyCode), eventType == EMSCRIPTEN_EVENT_KEYDOWN);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
EM_BOOL resizeCallback(int eventType, const EmscriptenUiEvent *e, void *userData) {
|
||||
// Core::width = e->documentBodyClientWidth;
|
||||
// Core::height = e->documentBodyClientHeight;
|
||||
int f;
|
||||
emscripten_get_canvas_size(&Core::width, &Core::height, &f);
|
||||
LOG("resize %d x %d\n", Core::width, Core::height);
|
||||
return 1;
|
||||
}
|
||||
|
||||
EM_BOOL touchCallback(int eventType, const EmscriptenTouchEvent *e, void *userData) {
|
||||
bool flag = false;
|
||||
/*
|
||||
for (int i = 0; i < e->numTouches; i++) {
|
||||
long x = e->touches[i].canvasX;
|
||||
long y = e->touches[i].canvasY;
|
||||
if (x < 0 || y < 0 || x >= Core::width || y >= Core::height) continue;
|
||||
flag = true;
|
||||
|
||||
switch (eventType) {
|
||||
case EMSCRIPTEN_EVENT_TOUCHSTART :
|
||||
if (x > Core::width / 2)
|
||||
Input::joy.down[(y > Core::height / 2) ? 1 : 4] = true;
|
||||
break;
|
||||
case EMSCRIPTEN_EVENT_TOUCHMOVE :
|
||||
if (x < Core::width / 2) {
|
||||
vec2 center(Core::width * 0.25f, Core::height * 0.6f);
|
||||
vec2 pos(x, y);
|
||||
vec2 d = pos - center;
|
||||
|
||||
Input::Joystick &joy = Input::joy;
|
||||
|
||||
joy.L.x = d.x;
|
||||
joy.L.y = d.y;
|
||||
if (joy.L != vec2(0.0f))
|
||||
joy.L.normalize();
|
||||
}
|
||||
break;
|
||||
case EMSCRIPTEN_EVENT_TOUCHEND :
|
||||
case EMSCRIPTEN_EVENT_TOUCHCANCEL : {
|
||||
Input::joy.L = vec2(0.0f);
|
||||
Input::joy.down[1] = false;
|
||||
Input::joy.down[4] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return flag;
|
||||
}
|
||||
|
||||
EM_BOOL mouseCallback(int eventType, const EmscriptenMouseEvent *e, void *userData) {
|
||||
switch (eventType) {
|
||||
case EMSCRIPTEN_EVENT_MOUSEDOWN :
|
||||
case EMSCRIPTEN_EVENT_MOUSEUP : {
|
||||
InputKey key = e->button == 0 ? ikMouseL : (e->button == 2 ? ikMouseR : ikMouseM);
|
||||
Input::setPos(key, vec2((float)e->clientX, (float)e->clientY));
|
||||
Input::setDown(key, eventType != EMSCRIPTEN_EVENT_MOUSEUP);
|
||||
break;
|
||||
}
|
||||
case EMSCRIPTEN_EVENT_MOUSEMOVE :
|
||||
Input::setPos(ikMouseL, vec2((float)e->clientX, (float)e->clientY));
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main() {
|
||||
initGL();
|
||||
|
||||
emscripten_set_canvas_size(Core::width = 1280, Core::height = 720);
|
||||
|
||||
emscripten_set_keydown_callback(0, 0, 1, keyCallback);
|
||||
emscripten_set_keyup_callback(0, 0, 1, keyCallback);
|
||||
emscripten_set_resize_callback(0, 0, 1, resizeCallback);
|
||||
|
||||
emscripten_set_touchstart_callback(0, 0, 1, touchCallback);
|
||||
emscripten_set_touchend_callback(0, 0, 1, touchCallback);
|
||||
emscripten_set_touchmove_callback(0, 0, 1, touchCallback);
|
||||
emscripten_set_touchcancel_callback(0, 0, 1, touchCallback);
|
||||
|
||||
emscripten_set_mousedown_callback(0, 0, 1, mouseCallback);
|
||||
emscripten_set_mouseup_callback(0, 0, 1, mouseCallback);
|
||||
emscripten_set_mousemove_callback(0, 0, 1, mouseCallback);
|
||||
|
||||
Game::init();
|
||||
|
||||
lastTime = getTime();
|
||||
fpsTime = lastTime + 1000;
|
||||
FPS = 0;
|
||||
|
||||
emscripten_set_main_loop(main_loop, 0, true);
|
||||
|
||||
Game::free();
|
||||
freeGL();
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user