diff --git a/examples/01.HelloWorld_emscripten/Makefile b/examples/01.HelloWorld_emscripten/Makefile new file mode 100644 index 00000000..45f74a3b --- /dev/null +++ b/examples/01.HelloWorld_emscripten/Makefile @@ -0,0 +1,68 @@ +# Makefile for Irrlicht Examples +# It's usually sufficient to change just the target name and source file list +# and be sure that CXX is set to a valid compiler + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 01.HelloWorld +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +all_emscripten: EMSCRIPTEN=1 + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG + ifdef EMSCRIPTEN + LDFLAGS += -s DEMANGLE_SUPPORT=1 + endif + CXXFLAGS += -g -Wall +else + ifdef EMSCRIPTEN + LDFLAGS += -O3 + endif + CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings + ll_linux all_emscripten all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_emscripten clean_emscripten: SYSTEM=emscripten +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +all_emscripten clean_emscripten: SUF=.html +all_emscripten: CXXFLAGS += -fno-exceptions -fno-rtti -fstrict-aliasing -std=gnu++11 -U__STRICT_ANSI__ +all_emscripten: LDFLAGS += -lGLESv2 -s FULL_ES2=1 -lSDL --preload-file ../../media@/media -s ALLOW_MEMORY_GROWTH=1 +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 all_emscripten static_win32: + $(warning Building...) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS) + +clean: clean_linux clean_win32 clean_emscripten + $(warning Cleaning...) + +clean_linux clean_win32 clean_emscripten: + @$(RM) $(DESTPATH) + +.PHONY: all all_win32 all_emscripten static_win32 clean clean_linux clean_win32 clean_emscripten + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/01.HelloWorld_emscripten/main.cpp b/examples/01.HelloWorld_emscripten/main.cpp new file mode 100644 index 00000000..f11f47ca --- /dev/null +++ b/examples/01.HelloWorld_emscripten/main.cpp @@ -0,0 +1,279 @@ +/** Example 001 HelloWorld + +This Tutorial shows how to set up the IDE for using the Irrlicht Engine and how +to write a simple HelloWorld program with it. The program will show how to use +the basics of the VideoDriver, the GUIEnvironment, and the SceneManager. +Microsoft Visual Studio is used as an IDE, but you will also be able to +understand everything if you are using a different one or even another +operating system than windows. + +You have to include the header file in order to use the engine. The +header file can be found in the Irrlicht Engine SDK directory \c include. To let +the compiler find this header file, the directory where it is located has to be +specified. This is different for every IDE and compiler you use. Let's explain +shortly how to do this in Microsoft Visual Studio: + +- If you use Version 6.0, select the Menu Extras -> Options. + Select the directories tab, and select the 'Include' Item in the combo box. + Add the \c include directory of the irrlicht engine folder to the list of + directories. Now the compiler will find the Irrlicht.h header file. We also + need the irrlicht.lib to be found, so stay in that dialog, select 'Libraries' + in the combo box and add the \c lib/VisualStudio directory. + \image html "vc6optionsdir.jpg" + \image latex "vc6optionsdir.jpg" + \image html "vc6include.jpg" + \image latex "vc6include.jpg" + +- If your IDE is Visual Studio .NET, select Tools -> Options. + Select the projects entry and then select VC++ directories. Select 'show + directories for include files' in the combo box, and add the \c include + directory of the irrlicht engine folder to the list of directories. Now the + compiler will find the Irrlicht.h header file. We also need the irrlicht.lib + to be found, so stay in that dialog, select 'show directories for Library + files' and add the \c lib/VisualStudio directory. + \image html "vcnetinclude.jpg" + \image latex "vcnetinclude.jpg" + +That's it. With your IDE set up like this, you will now be able to develop +applications with the Irrlicht Engine. + +Lets start! + +After we have set up the IDE, the compiler will know where to find the Irrlicht +Engine header files so we can include it now in our code. +*/ +#include +#include "exampleHelper.h" +#include +#include + +/* +In the Irrlicht Engine, everything can be found in the namespace 'irr'. So if +you want to use a class of the engine, you have to write irr:: before the name +of the class. For example to use the IrrlichtDevice write: irr::IrrlichtDevice. +To get rid of the irr:: in front of the name of every class, we tell the +compiler that we use that namespace from now on, and we will not have to write +irr:: anymore. +*/ +using namespace irr; + +/* +There are 5 sub namespaces in the Irrlicht Engine. Take a look at them, you can +read a detailed description of them in the documentation by clicking on the top +menu item 'Namespace List' or by using this link: +http://irrlicht.sourceforge.net/docu/namespaces.html +Like the irr namespace, we do not want these 5 sub namespaces now, to keep this +example simple. Hence, we tell the compiler again that we do not want always to +write their names. +*/ +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +/* +To be able to use the Irrlicht.DLL file, we need to link with the Irrlicht.lib. +We could set this option in the project settings, but to make it easy, we use a +pragma comment lib for VisualStudio. On Windows platforms, we have to get rid +of the console window, which pops up when starting a program with main(). This +is done by the second pragma. We could also use the WinMain method, though +losing platform independence then. +*/ +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") +#endif + +IrrlichtDevice *device = 0; +IVideoDriver* driver = 0; +ISceneManager* smgr = 0; +IGUIEnvironment* guienv = 0; + +/* + emscripten can't run things in an endless-loop or otherwise the browse will consider + the script to hang. +*/ +#ifdef __EMSCRIPTEN__ +void one_iter() +{ + if(!device->run()) + { + //emscripten_cancel_main_loop(); + return; + } + driver->beginScene(ECBF_COLOR | ECBF_DEPTH, SColor(255,100,101,140)); + + smgr->drawAll(); + guienv->drawAll(); + + driver->endScene(); +} +#endif //__EMSCRIPTEN__ + + +/* +This is the main method. We can now use main() on every platform. +*/ +int main() +{ + /* + The most important function of the engine is the createDevice() + function. The IrrlichtDevice is created by it, which is the root + object for doing anything with the engine. createDevice() has 7 + parameters: + + - deviceType: Type of the device. This can currently be the Null-device, + one of the two software renderers, D3D9, or OpenGL. In this + example we use EDT_SOFTWARE, but to try out, you might want to + change it to EDT_BURNINGSVIDEO, EDT_NULL, EDT_DIRECT3D9, or EDT_OPENGL. + + - windowSize: Size of the Window or screen in FullScreenMode to be + created. In this example we use 640x480. + + - bits: Amount of color bits per pixel. This should be 16 or 32. The + parameter is often ignored when running in windowed mode. + + - fullscreen: Specifies if we want the device to run in fullscreen mode + or not. + + - stencilbuffer: Specifies if we want to use the stencil buffer (for + drawing shadows). + + - vsync: Specifies if we want to have vsync enabled, this is only useful + in fullscreen mode. + + - eventReceiver: An object to receive events. We do not want to use this + parameter here, and set it to 0. + + Always check the return value to cope with unsupported drivers, + dimensions, etc. + */ +#ifndef __EMSCRIPTEN__ + device = + createDevice( video::EDT_OGLES1, dimension2d(640, 480), 16, + false, false, false, 0); +#else //__EMSCRIPTEN__ + device = + createDevice(video::EDT_OGLES2, dimension2d(640, 480), 16, + false, false, false, 0); ++#endif //__EMSCRIPTEN__ + + if (!device) + return 1; + + /* + Set the caption of the window to some nice text. Note that there is an + 'L' in front of the string. The Irrlicht Engine uses wide character + strings when displaying text. + */ + device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo"); + + /* + Get a pointer to the VideoDriver, the SceneManager and the graphical + user interface environment, so that we do not always have to write + device->getVideoDriver(), device->getSceneManager(), or + device->getGUIEnvironment(). + */ + driver = device->getVideoDriver(); + smgr = device->getSceneManager(); + guienv = device->getGUIEnvironment(); + + /* + We add a hello world label to the window, using the GUI environment. + The text is placed at the position (10,10) as top left corner and + (260,22) as lower right corner. + */ + guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!", + rect(10,10,260,22), true); + + /* + Get a media path dedicated for your platform. + */ + const io::path mediaPath = getExampleMediaPath(); + + /* + To show something interesting, we load a Quake 2 model and display it. + We only have to get the Mesh from the Scene Manager with getMesh() and add + a SceneNode to display the mesh with addAnimatedMeshSceneNode(). We + check the return value of getMesh() to become aware of loading problems + and other errors. + + Instead of writing the filename sydney.md2, it would also be possible + to load a Maya object file (.obj), a complete Quake3 map (.bsp) or any + other supported file format. By the way, that cool Quake 2 model + called sydney was modelled by Brian Collins. + */ + IAnimatedMesh* mesh = smgr->getMesh(mediaPath + "sydney.md2"); + if (!mesh) + { + device->drop(); + return 1; + } + IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + + /* + To let the mesh look a little bit nicer, we change its material. We + disable lighting because we do not have a dynamic light in here, and + the mesh would be totally black otherwise. Then we set the frame loop, + such that the predefined STAND animation is used. And last, we apply a + texture to the mesh. Without it the mesh would be drawn using only a + color. + */ + if (node) + { + node->setMaterialFlag(EMF_LIGHTING, false); + node->setMD2Animation(scene::EMAT_STAND); + node->setMaterialTexture( 0, driver->getTexture(mediaPath + "sydney.bmp") ); + } + + /* + To look at the mesh, we place a camera into 3d space at the position + (0, 30, -40). The camera looks from there to (0,5,0), which is + approximately the place where our md2 model is. + */ + smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); + + /* + Ok, now we have set up the scene, lets draw everything: We run the + device in a while() loop, until the device does not want to run any + more. This would be when the user closes the window or presses ALT+F4 + (or whatever keycode closes a window). + */ + while(device->run()) + { + /* + Anything can be drawn between a beginScene() and an endScene() + call. The beginScene() call clears the screen with a color and + the depth buffer, if desired. Then we let the Scene Manager and + the GUI Environment draw their content. With the endScene() + call everything is presented on the screen. + */ + driver->beginScene(ECBF_COLOR | ECBF_DEPTH, SColor(255,100,101,140)); + + smgr->drawAll(); + guienv->drawAll(); + + driver->endScene(); + } + ++#ifndef __EMSCRIPTEN__ + /* + After we are done with the render loop, we have to delete the Irrlicht + Device created before with createDevice(). In the Irrlicht Engine, you + have to delete all objects you created with a method or function which + starts with 'create'. The object is simply deleted by calling ->drop(). + See the documentation at irr::IReferenceCounted::drop() for more + information. + */ + device->drop(); +#else // __EMSCRIPTEN__ + emscripten_set_main_loop(one_iter, 0, 0); +#endif //__EMSCRIPTEN__ + + return 0; +} + +/* +That's it. Compile and run. +**/ diff --git a/examples/01.HelloWorld_emscripten/readme.txt b/examples/01.HelloWorld_emscripten/readme.txt new file mode 100644 index 00000000..aa608bab --- /dev/null +++ b/examples/01.HelloWorld_emscripten/readme.txt @@ -0,0 +1,5 @@ +emscripten is a project to compile c/c++ code int the asm.js format which can be run in some browsers. +See http://kripken.github.io/emscripten-site for more information. + +emscripten support for Irrlicht is a work in process. Use at your own risk. +Might take work and knowledge to get it running. diff --git a/examples/01.HelloWorld_emscripten/tutorial.html b/examples/01.HelloWorld_emscripten/tutorial.html new file mode 100644 index 00000000..e46c9542 --- /dev/null +++ b/examples/01.HelloWorld_emscripten/tutorial.html @@ -0,0 +1,394 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + + +
Tutorial 1.HelloWorld
+

This Tutorial shows how to set up the IDE for using the + Irrlicht Engine and how to write a simple HelloWorld program + with it. The program will show how to use the basics of + the VideoDriver, the GUIEnvironment and the SceneManager.
+ The result of this example will look like this:

+


+

+
+
+ + + + + + +
Setting up the + IDE
+
+

To use the engine, we will have to include + the header file <irrlicht.h>, which can be found + in the Irrlicht Engine SDK directory \include. To let + the compiler find this header file, the directory where + it is located should be specified somewhere. This is different + for every IDE and compiler. I will explain how to do this + in Microsoft Visual Studio C++ 6.0 and .NET:

+ +
+
    +
  • +
    If you use Version 6.0, select the Menu + Extras -> Options. Select the directories tab, and + select the 'Include' Item in the combo box. Add the + \include directory of the Irrlicht Engine folder to + the list of directories. Now the compiler will find + the Irrlicht.h header file. We also need the location + of irrlicht.lib to be listed, so select the 'Libraries' + tab and add the \lib\VisualStudio directory.
    +
    +   
    +  
    + +
    +
  • +
  • If your IDE is Visual Studio .NET, select Tools -> + Options. Select the Projects entry and then select VC++ + directories. Select 'show directories for include files' + in the combo box, and add the \include directory of the + Irrlicht Engine folder to the list of directories so the + compiler will find the Irrlicht.h header file. We also + need the irrlicht.lib to be found, so select 'show directories + for Library files' and add the \lib\VisualStudio directory.
    +
    + +
    +
  • +
+ +

 

+
+
+ + + + + + + + +
Lets start!
+
+
+
+

After we have set up the IDE, the compiler will know + where to find the Irrlicht Engine header files so + we can include it now into our code.

+ + + + + +
#include <irrlicht.h>
+

In the Irrlicht Engine, everything can be found in + the namespace 'irr'. So if you want to use a class + of the engine, you'll have to type an irr:: before + the name of the class. For example, to use the IrrlichtDevice, + write: irr::IrrlichtDevice. To avoid having to put + irr:: before of the name of every class, we tell the + compiler that we use that namespace.

+ + + + + +
using namespace irr;
+

There are 5 sub-namespaces in the Irrlicht Engine. + Take a look at them: you can read a detailed description + of them in the documentation by clicking on the top + menu item 'Namespace + List'. To keep this example simple, we don't want + to have to specify the name spaces, Hence:

+ + + + + +
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
+

To be able to use the Irrlicht.DLL file, we need + to link with the Irrlicht.lib. We could set this option + in the project settings, but to make it easy we use + a pragma comment:

+ + + + + +
#pragma comment(lib, "Irrlicht.lib")
+

Now the main method: to keep this example simple + we use int main(), which can be used on any platform. + However, on Windows platforms, we could also use the + WinMain method if we would want to get rid of the + console window which pops up when starting a program + with main().

+ + + + + +
int main()
{
+

The most important function of the engine is the + 'createDevice' function. The Irrlicht Device, which + is the root object for doing everything with the engine, + can be created with it. createDevice() has 7 parameters:

+
+
    +
  • + +
    deviceType: Type of the device. This can currently + be the Null device, the Software device, Direct3D8, Direct3D9, + or OpenGL. In this example we use EDT_SOFTWARE, but, to try + them out, you might want to change it to EDT_NULL, EDT_DIRECT3D8, + EDT_DIRECT3D9 or EDT_OPENGL.
    +
  • +
  • +
    windowSize: Size of the window or + full screen mode to be created. In this example + we use 512x384.
    + +
  • +
  • +
    bits: Number of bits per pixel when + in full screen mode. This should be 16 or 32. This + parameter is ignored when running in windowed mode.
    +
  • +
  • +
    fullscreen: Specifies if we want + the device to run in full screen mode or not.
    +
  • +
  • stencilbuffer: Specifies if we want to use the stencil + buffer for drawing shadows.
  • + +
  • vsync: Specifies if we want to have vsync enabled. + This is only useful in full screen mode.
  • +
  • +
    eventReceiver: An object to receive + events. We do not want to use this parameter here, + and set it to 0.
    +
  • +
+ + + + + +
IrrlichtDevice *device =
createDevice(EDT_SOFTWARE, dimension2d<s32>(512, 384), 16,
false, false, false, 0);
+

Now we set the caption of the window to some nice text. + Note that there is a 'L' in front of the string: the + Irrlicht Engine uses wide character strings when displaying + text.

+ + + + + +
device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");
+

Now we store a pointer to the video driver, the SceneManager, + and the graphical user interface environment so that + we do not always have to write device->getVideoDriver(), + device->getSceneManager(), and device->getGUIEnvironment().

+ + + + + +
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* guienv = device->getGUIEnvironment();
+

We add a hello world label to the window using the + GUI environment. The text is placed at the position + (10,10) as top left corner and (200,22) as lower right + corner.

+ + + + + +
guienv->addStaticText(L"Hello World! This is the Irrlicht Software engine!",
rect<s32>(10,10,200,22), true);
+

To display something interesting, we load a Quake 2 + model and display it. We only have to get the Mesh from + the Scene Manager with getMesh() and add a SceneNode + to display the mesh with addAnimatedMeshSceneNode(). + Instead of loading a Quake2 file (.md2), it is also + possible to load a Maya object file (.obj), a complete + Quake3 map (.bsp), or a Milshape file (.ms3d).
+ By the way, that cool Quake 2 model called sydney.md2 + was modelled by Brian Collins.

+ + + + + +
IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
+

To make the mesh look a little bit nicer, we change + its material a little bit: we disable lighting because + we do not have a dynamic light in here and the mesh + would be totally black. Then we set the frame loop so + that the animation is looped between the frames 0 and + 310. Then, at last, we apply a texture to the mesh. + Without it the mesh would be drawn using only a solid + color.

+ + + + + +
if (node)
{
node->setMaterialFlag(EMF_LIGHTING, false);
node->setFrameLoop(0, 310);
node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") );
}
+
+

To look at the mesh, we place a camera into 3d space + at the position (0, 10, -40). The camera looks from + there to (0,5,0).

+ + + + + +
smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
+

Ok. Now that we have set up the scene, let's draw everything: + we run the device in a while() loop until the device + does not want to run any more. This would be when the + user closes the window or presses ALT+F4 in Windows.

+ + + + + +
while(device->run())
{
+

Everything must be drawn between a beginScene() and + an endScene() call. The beginScene clears the screen + with a color and also the depth buffer, if desired. + Then we let the Scene Manager and the GUI environment + draw their content. With the endScene() call, everything + is presented on the screen.

+ + + + + + +
	driver->beginScene(true, true, SColor(255,100,101,140));
+ smgr->drawAll(); + guienv->drawAll();
+
	driver->endScene();
+}
+

After we are finished, we have to delete the Irrlicht + Device created earlier with createDevice(). With the + Irrlicht Engine, you should delete all objects you created + with a method or function that starts with 'create'. + The object is deleted simply by calling ->drop(). + See the documentation + for more information.

+ + + + + +
	device->drop();
return 0; +}
+

That's it. Compile and run.

+

 

+
+
+
+
+ + + + + + + +
Possible Errors + or Problems
+
+
+

Visual Studio
+ + While trying to compile the tutorial, if you get the + error:

+ + + + +
fatal + error C1083: Cannot open include file: 'irrlicht.h': + No such file or directory
+

Solution: You may have set the include directory improperly + in the Visual Studio options. See above + for information on setting it.

+ + + + + +
LINK + : LNK6004: HelloWorld.exe not found or not built + by the last incremental link; performing full link
+ LINK : fatal error LNK1104: cannot open file "Irrlicht.lib"
+ Error executing link.exe
+

Solution: You may have set the library directory improperly. + See above for information on + setting it.
+ +
+

+

Compiler independent problems
+
If the tutorial compiles successfully but gives + the error:

+ + + + + +
This + application has failed to start because Irrlicht.dll + was not found. Re-installing the application may + fix this problem
+

Solution: You may have forgotten to copy the Irrlicht.dll + file from Irrlicht\bin\VisualStudio to the directory + the tutorial's project file is in.

+ If the tutorial compiles and runs successfully but produces + errors in the console like:
+
+ + + + + +
Could + not load mesh, because file could not be opened.: + ../media/sydney.md2
+

Or:

+ + + + + +
Could + not open file of texture: stones.jpg
+
Could not load texture: stones.jpg
+

Solution: The file listed in the error message cannot + be found. Ensure that the directory specified in the + main.cpp exists and is where the file is located.
+

+
+
+
+

 

+ + diff --git a/include/IrrCompileConfig.h b/include/IrrCompileConfig.h index 05bb89e8..4adaa67d 100644 --- a/include/IrrCompileConfig.h +++ b/include/IrrCompileConfig.h @@ -100,6 +100,18 @@ #endif #endif +#if defined(__EMSCRIPTEN__) +#define _IRR_EMSCRIPTEN_PLATFORM_ +#define NO_IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +#define NO_IRR_COMPILE_WITH_OPENGL_ +#define NO_IRR_COMPILE_WITH_OGLES1_ +#define _IRR_COMPILE_WITH_OGLES2_ +#define _IRR_COMPILE_WITH_EGL_MANAGER_ +#define _IRR_COMPILE_WITH_SDL_DEVICE_ +#define NO_IRR_COMPILE_WITH_X11_DEVICE_ +//#define _IRR_LINUX_PLATFORM_ //Hack +#endif // __EMSCRIPTEN__ + #if defined(__ANDROID__) #define _IRR_ANDROID_PLATFORM_ #define _IRR_COMPILE_WITH_ANDROID_DEVICE_ @@ -114,7 +126,7 @@ #endif #endif -#if !defined(_IRR_WINDOWS_API_) && !defined(_IRR_OSX_PLATFORM_) && !defined(_IRR_IOS_PLATFORM_) && !defined(_IRR_ANDROID_PLATFORM_) +#if !defined(_IRR_WINDOWS_API_) && !defined(_IRR_OSX_PLATFORM_) && !defined(_IRR_IOS_PLATFORM_) && !defined(_IRR_ANDROID_PLATFORM_) && !defined(_IRR_EMSCRIPTEN_PLATFORM_) #ifndef _IRR_SOLARIS_PLATFORM_ #define _IRR_LINUX_PLATFORM_ #endif diff --git a/include/SIrrCreationParameters.h b/include/SIrrCreationParameters.h index 09c84f25..0e94a0f8 100644 --- a/include/SIrrCreationParameters.h +++ b/include/SIrrCreationParameters.h @@ -51,7 +51,7 @@ namespace irr UsePerformanceTimer(true), SDK_version_do_not_use(IRRLICHT_SDK_VERSION), PrivateData(0), -#if defined(_IRR_COMPILE_WITH_IOS_DEVICE_) || defined(_IRR_ANDROID_PLATFORM_) +#if defined(_IRR_COMPILE_WITH_IOS_DEVICE_) || defined(_IRR_ANDROID_PLATFORM_) || defined(_IRR_EMSCRIPTEN_PLATFORM_) OGLES2ShaderPath("media/Shaders/") #else OGLES2ShaderPath("../../media/Shaders/") diff --git a/include/exampleHelper.h b/include/exampleHelper.h index ce9b297b..e1e7cb2e 100755 --- a/include/exampleHelper.h +++ b/include/exampleHelper.h @@ -13,7 +13,7 @@ namespace irr static io::path getExampleMediaPath() { -#if defined (_IRR_IOS_PLATFORM_) || defined (_IRR_ANDROID_PLATFORM_) || defined (_IRR_OSX_PLATFORM_) +#if defined (_IRR_IOS_PLATFORM_) || defined (_IRR_ANDROID_PLATFORM_) || defined (_IRR_OSX_PLATFORM_) || defined (_IRR_EMSCRIPTEN_PLATFORM_) return io::path("media/"); #else return io::path("../../media/"); diff --git a/source/Irrlicht/CEGLManager.h b/source/Irrlicht/CEGLManager.h index 856de137..2ba666c7 100755 --- a/source/Irrlicht/CEGLManager.h +++ b/source/Irrlicht/CEGLManager.h @@ -9,7 +9,7 @@ #ifdef _IRR_COMPILE_WITH_EGL_MANAGER_ -#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) || defined(_IRR_COMPILE_WITH_FB_DEVICE_) || defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) +#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) || defined(_IRR_COMPILE_WITH_FB_DEVICE_) || defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(__EMSCRIPTEN__) #include #else #include diff --git a/source/Irrlicht/CFileSystem.cpp b/source/Irrlicht/CFileSystem.cpp index 8d152c12..60420d28 100644 --- a/source/Irrlicht/CFileSystem.cpp +++ b/source/Irrlicht/CFileSystem.cpp @@ -35,8 +35,7 @@ #include // for _access #include #endif -#else - #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_) || defined(_IRR_IOS_PLATFORM_) || defined(_IRR_ANDROID_PLATFORM_)) +#elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_) || defined(_IRR_IOS_PLATFORM_) || defined(_IRR_ANDROID_PLATFORM_)) #include #include #include @@ -45,7 +44,8 @@ #include #include #include - #endif +#elif defined(_IRR_EMSCRIPTEN_PLATFORM_) + #include #endif namespace irr diff --git a/source/Irrlicht/CIrrDeviceSDL.cpp b/source/Irrlicht/CIrrDeviceSDL.cpp index d47e256f..56760699 100644 --- a/source/Irrlicht/CIrrDeviceSDL.cpp +++ b/source/Irrlicht/CIrrDeviceSDL.cpp @@ -20,6 +20,13 @@ #include #include +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ +#ifdef _IRR_COMPILE_WITH_OGLES2_ +#include "CEGLManager.h" +#endif +#include +#endif + #ifdef _MSC_VER #pragma comment(lib, "SDL.lib") #endif // _MSC_VER @@ -37,6 +44,10 @@ namespace irr IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, CIrrDeviceSDL* device); #endif + + #if defined(_IRR_COMPILE_WITH_OGLES2_) && defined(_IRR_EMSCRIPTEN_PLATFORM_) + IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + #endif } // end namespace video } // end namespace irr @@ -73,14 +84,16 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters& param) SDL_putenv("SDL_VIDEODRIVER=directx"); #elif defined(_IRR_OSX_PLATFORM_) SDL_putenv("SDL_VIDEODRIVER=Quartz"); -#else +#elif !defined(_IRR_EMSCRIPTEN_PLATFORM_) SDL_putenv("SDL_VIDEODRIVER=x11"); #endif // SDL_putenv("SDL_WINDOWID="); SDL_VERSION(&Info.version); +#ifndef _IRR_EMSCRIPTEN_PLATFORM_ SDL_GetWMInfo(&Info); +#endif //_IRR_EMSCRIPTEN_PLATFORM_ core::stringc sdlversion = "SDL Version "; sdlversion += Info.version.major; sdlversion += "."; @@ -104,6 +117,11 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters& param) SDL_Flags |= SDL_OPENGL; else if (CreationParams.Doublebuffer) SDL_Flags |= SDL_DOUBLEBUF; +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + else + SDL_Flags = SDL_SWSURFACE; +#endif //_IRR_EMSCRIPTEN_PLATFORM_ + // create window if (CreationParams.DriverType != video::EDT_NULL) { @@ -136,6 +154,10 @@ CIrrDeviceSDL::~CIrrDeviceSDL() bool CIrrDeviceSDL::createWindow() { +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + emscripten_set_canvas_size( Width, Height); + return true; +#else // !_IRR_EMSCRIPTEN_PLATFORM_ if ( Close ) return false; @@ -204,6 +226,7 @@ bool CIrrDeviceSDL::createWindow() } return true; +#endif // !_IRR_EMSCRIPTEN_PLATFORM_ } @@ -254,6 +277,21 @@ void CIrrDeviceSDL::createDriver() #endif break; + case video::EDT_OGLES2: +#if defined(_IRR_COMPILE_WITH_OGLES2_) && defined(_IRR_EMSCRIPTEN_PLATFORM_) + { + video::SExposedVideoData data; + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); + + VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); + } +#else + os::Printer::log("No OpenGL-ES2 support compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_NULL: VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); break; @@ -420,7 +458,11 @@ bool CIrrDeviceSDL::run() { Width = SDL_event.resize.w; Height = SDL_event.resize.h; - Screen = SDL_SetVideoMode( Width, Height, 0, SDL_Flags ); +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + emscripten_set_canvas_size( Width, Height); +#else //_IRR_EMSCRIPTEN_PLATFORM_ + Screen = SDL_SetVideoMode( Width, Height, 0, SDL_Flags ); +#endif //_IRR_EMSCRIPTEN_PLATFOR if (VideoDriver) VideoDriver->OnResize(core::dimension2d(Width, Height)); } @@ -600,6 +642,9 @@ void CIrrDeviceSDL::setWindowCaption(const wchar_t* text) //! presents a surface in the client area bool CIrrDeviceSDL::present(video::IImage* surface, void* windowId, core::rect* srcClip) { +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + return true; +#else // !_IRR_EMSCRIPTEN_PLATFORM_ SDL_Surface *sdlSurface = SDL_CreateRGBSurfaceFrom( surface->lock(), surface->getDimension().Width, surface->getDimension().Height, surface->getBitsPerPixel(), surface->getPitch(), @@ -675,6 +720,7 @@ bool CIrrDeviceSDL::present(video::IImage* surface, void* windowId, core::rectunlock(); return (scr != 0); +#endif // !_IRR_EMSCRIPTEN_PLATFORM_ } @@ -688,6 +734,10 @@ void CIrrDeviceSDL::closeDevice() //! \return Pointer to a list with all video modes supported video::IVideoModeList* CIrrDeviceSDL::getVideoModeList() { +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + os::Printer::log("VideoModeList not available on the web." , ELL_WARNING); + return VideoModeList; +#elif // !_IRR_EMSCRIPTEN_PLATFORM_ if (!VideoModeList->getVideoModeCount()) { // enumerate video modes. @@ -706,12 +756,17 @@ video::IVideoModeList* CIrrDeviceSDL::getVideoModeList() } return VideoModeList; +#endif // !_IRR_EMSCRIPTEN_PLATFORM_ } //! Sets if the window should be resizable in windowed mode. void CIrrDeviceSDL::setResizable(bool resize) { +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + os::Printer::log("Resizable not available on the web." , ELL_WARNING); + return; +#elif // !_IRR_EMSCRIPTEN_PLATFORM_ if (resize != Resizable) { if (resize) @@ -721,6 +776,7 @@ void CIrrDeviceSDL::setResizable(bool resize) Screen = SDL_SetVideoMode( 0, 0, 0, SDL_Flags ); Resizable = resize; } +#endif // !_IRR_EMSCRIPTEN_PLATFORM_ } diff --git a/source/Irrlicht/Makefile b/source/Irrlicht/Makefile index f7e1dd9e..d131dcb8 100644 --- a/source/Irrlicht/Makefile +++ b/source/Irrlicht/Makefile @@ -59,6 +59,8 @@ LINKOBJ = $(IRRMESHOBJ) $(IRROBJ) $(IRRPARTICLEOBJ) $(IRRANIMOBJ) \ $(IRRGUIOBJ) $(ZLIBOBJ) $(JPEGLIBOBJ) $(LIBPNGOBJ) $(LIBAESGM) \ $(BZIP2OBJ) $(EXTRAOBJ) +emscripten: EMSCRIPTEN=1 + ############### #Compiler flags @@ -66,14 +68,27 @@ CXXINCS = -I../../include -Izlib -Ijpeglib -Ilibpng CPPFLAGS += $(CXXINCS) -DIRRLICHT_EXPORTS=1 CXXFLAGS += -Wall -pipe -fno-exceptions -fno-rtti -fstrict-aliasing ifndef NDEBUG -CXXFLAGS += -g -D_DEBUG + CXXFLAGS += -g -D_DEBUG else -CXXFLAGS += -fexpensive-optimizations -O3 + ifndef EMSCRIPTEN + CXXFLAGS += -fexpensive-optimizations -O3 + else + CXXFLAGS += -O3 + endif endif ifdef PROFILE -CXXFLAGS += -pg + CXXFLAGS += -pg +endif +ifdef EMSCRIPTEN + CXXFLAGS += -std=gnu++11 -U__STRICT_ANSI__ + ifndef NDEBUG + CFLAGS := -DPNG_THREAD_UNSAFE_OK -DPNG_NO_MMX_CODE -DPNG_NO_MNG_FEATURES + else + CFLAGS := -O3 -DPNG_THREAD_UNSAFE_OK -DPNG_NO_MMX_CODE -DPNG_NO_MNG_FEATURES + endif +else + CFLAGS := -O3 -fexpensive-optimizations -DPNG_THREAD_UNSAFE_OK -DPNG_NO_MMX_CODE -DPNG_NO_MNG_FEATURES endif -CFLAGS := -O3 -fexpensive-optimizations -DPNG_THREAD_UNSAFE_OK -DPNG_NO_MMX_CODE -DPNG_NO_MNG_FEATURES sharedlib sharedlib_osx: CXXFLAGS += -fPIC sharedlib sharedlib_osx: CFLAGS += -fPIC @@ -117,7 +132,7 @@ SONAME = $(SHARED_LIB).$(VERSION_MAJOR).$(VERSION_MINOR) #################### # All target, builds Irrlicht as static lib (libIrrlicht.a) and copies it into lib/Linux -all linux: staticlib +all linux emscripten: staticlib # Builds Irrlicht as shared lib (libIrrlicht.so.versionNumber) and copies it into lib/Linux sharedlib: $(LINKOBJ) @@ -163,7 +178,7 @@ TAGS: # Create dependency files for automatic recompilation %.d:%.cpp - $(CXX) $(CPPFLAGS) -MM -MF $@ $< + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MM -MF $@ $< # Create dependency files for automatic recompilation %.d:%.c @@ -192,5 +207,4 @@ help: clean: $(RM) $(LINKOBJ) $(SHARED_FULLNAME) $(STATIC_LIB) $(LINKOBJ:.o=.d) -.PHONY: all sharedlib staticlib sharedlib_win32 staticlib_win32 help install clean - +.PHONY: all sharedlib staticlib sharedlib_win32 staticlib_win32 emscripten help install clean diff --git a/source/Irrlicht/os.cpp b/source/Irrlicht/os.cpp index 96b8abdf..c43ee94c 100644 --- a/source/Irrlicht/os.cpp +++ b/source/Irrlicht/os.cpp @@ -189,6 +189,58 @@ namespace os } } // end namespace os +#elif defined(_IRR_EMSCRIPTEN_PLATFORM_) + +// ---------------------------------------------------------------- +// emscripten version +// ---------------------------------------------------------------- + +#include +#include +#include + +namespace irr +{ +namespace os +{ + + //! prints a debuginfo string + void Printer::print(const c8* message, ELOG_LEVEL ll) + { + int log_level; + switch (ll) + { + case ELL_DEBUG: + log_level=0; + break; + case ELL_INFORMATION: + log_level=0; + break; + case ELL_WARNING: + log_level=EM_LOG_WARN; + break; + case ELL_ERROR: + log_level=EM_LOG_ERROR; + break; + default: // ELL_NONE + log_level=0; + break; + } + emscripten_log(log_level, "%s\n", message); + } + + void Timer::initTimer(bool usePerformanceTimer) + { + initVirtualTimer(); + } + + u32 Timer::getRealTime() + { + double time = emscripten_get_now(); + return (u32)(time); + } +} // end namespace os + #else // ---------------------------------------------------------------- @@ -223,7 +275,7 @@ namespace os } } // end namespace os -#endif // end linux / android / windows +#endif // end linux / emscripten / android / windows namespace os {