1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-09 22:56:53 +02:00

WebGL platform

This commit is contained in:
XProger
2016-08-29 23:07:43 +03:00
parent 6af424cee8
commit a222a59cc7
11 changed files with 320 additions and 31 deletions

View File

@@ -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;
}

View File

@@ -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() {

View File

@@ -3,7 +3,7 @@
#include "utils.h"
//#define TR1_DEMO
#define TR1_DEMO
namespace TR {
#define DATA_PORTAL 0x01

View File

@@ -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() {

View File

@@ -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 : ;
}
}
}

View File

@@ -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();

View File

@@ -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));

View File

@@ -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
View 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
View 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
View 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;
}