away3d / away3d-core-broomstick Goto Github PK
View Code? Open in Web Editor NEWAway3D engine for Flash Player Incubator
Home Page: http://www.away3d.com
Away3D engine for Flash Player Incubator
Home Page: http://www.away3d.com
Loading a BMP fails as "unrecognized type". Probably because the suffix is not in the image parsers list of recognized suffixes. No reason not support it since Flash does.
Away3D, as is, causes this error when adding, removing, and re-adding View3D to the stage.
Main Thread (Suspended: Error: A Stage3D instance was already assigned!)
This is caused by the renderer's 3D proxy not being set to null. To fix this, we should be calling _renderer.dispose() and _depthRenderer.dispose() in the View3D.onRemovedFromStage() function. Note that RendererBase.dispose() does nothing except set this pointer to null.
After doing so, we get a successful call to onAddedToStage the 2nd time. However, the next call to render() bombs with the following callstack:
Main Thread (Suspended: Error: Error #3698: The back buffer is not configured.)
I use a Loader3D Instance to parse loaded Models.
_circuitParser = new OBJParser();
_circuitParser.addEventListener(ParserEvent.PARSE_COMPLETE, onResourceParserComplete);
_circuitLoader = new Loader3D(false);
_circuitLoader.parseData(_raceDTO.modelsDTO.circuitAsObj, _circuitParser, assetContext);
At onResourceParserComplete I tried to apply Materials on Meshes from _circuitLoader but only if I run DEBUG Mode Meshes are found.
Question: Are there any plans in future, for using OBJParser with recently loaded Models by a Framework?
Stage3D.viewport has gone.
"General authoring note: This release includes an update to the Stage3D APIs that removes the
Stage3D.viewport property. Developers should instead use the Stage3D.x and Stage3D.y properties.
Width and height can only be set using the Context3D object. Existing content using the Stage3D.viewport API will need to be updated to run with this and future builds of Flash Player and
AIR."
I'm digging a bit into materials and I'm finding out that lots of built in functions automatically invalidate shader programs.
This results in a frequent recompilation of the shaders lowering very much the fps.
what I suggest is:
The OBJParser currently goes rogue and loads it's MTL file itself, instead of relying on the dependency system. This is due to some shortcomings that existed in the dependency system at the time of writing the OBJParser, and which have since been corrected.
When a material is assigned to a mesh before an animation is initialized, the animation will fail to recognize that it needs to happen on the CPU, causing a crash due to exceeding the maximum number of program constants. Setting the material after having created the animation circumvents this but is not always possible.
I've posted this on the away3d forums as well.
ColorTransformMethod.as line 72
override arcane function activate(context : Context3D, contextIndex : uint) : void { _colorTransformData[0] = _colorTransform.redMultiplier; _colorTransformData[1] = _colorTransform.greenMultiplier; _colorTransformData[2] = _colorTransform.blueMultiplier; _colorTransformData[3] = _colorTransform.alphaMultiplier; _colorTransformData[4] = _colorTransform.redOffset; _colorTransformData[5] = _colorTransform.greenOffset; _colorTransformData[6] = _colorTransform.blueOffset; _colorTransformData[7] = _colorTransform.alphaOffset; context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, _colorTransformIndex, _colorTransformData, 2); }
the ColorTransform class asks for offsets between -255 and 255. However the shading code uses colors between 0 and 1. Additional code needs to be added to convert the offsets to the correct range.
Maybe this - not sure if the boundary conditions matter for the shader.
'_colorTransformData[4] = _colorTransform.redOffset / 0xff;
_colorTransformData[5] = _colorTransform.greenOffset / 0xff;
_colorTransformData[6] = _colorTransform.blueOffset / 0xff;
_colorTransformData[7] = _colorTransform.alphaOffset / 0xff;
'
Make sure that the following works, and if not, add them as features:
Add AssetLoaderContext.stopAtDependencyError property, defining whether load dependency queue should continue after a missing dependency, or stop.
Make sure errors are never thrown when there are error event listeners.
When a texture uses mipmapping but is not square, or when it's dimensions are not po2, a well-formulated error should be thrown explaining the issue at hand. Don't rescale the image behind the scenes, but make sure that the error explains what is actually the cause of the error better than the default player message "A texture sampler binds an incomplete texture".
When embedding images, they will by default be mx.core.BitmapAsset instances, meaning that a common mistake will be for users to have ImageParser try to parse data that is not actually a byte array, but instances of said class. Deal with that; either throw an informative error, or instantiate the class and return it's BitmapData as an asset directly (instead of using Loader.loadBytes() to load the bitmap.)
I experienced a memory leak in the rendering process. After a render call renderables still were refrenced by RenderableListItem s and RenderableListItem s still had references to the next.
I fixed the leak by
adding a function resetIndex to RenderableListItemPool,
editing the function freeAll in RenderableListItemPool,
and changing the calls EntityCollector performs to _renderableListItemPool instance.
Here's the changes:
RenderableListItemPool.as:
ADDED
public function resetIndex():void
{
_index = 0;
}
EDITED
public function freeAll() : void
{
var item:RenderableListItem;
while(_index-->0){
item = _pool[_index];
item.renderable = null;
item.next = null;
}
}
EntityCollector.as
[EDITED]
public function clear() : void
{
_numTriangles = _numMouseEnableds = 0;
_blendedRenderableHead = null;
_opaqueRenderableHead = null;
_renderableListItemPool.resetIndex(); // << call resetIndex instead of freeAll
if (_numLights > 0) _lights.length = _numLights = 0;
}
[EDITED]
public function cleanUp() : void
{
if (_numEntities > 0) {
for (var i : uint = 0; i < _numEntities; ++i)
_entities[i].popModelViewProjection();
_entities.length = _numEntities = 0;
_renderableListItemPool.freeAll(); // << added!
}
}
ciao,
pigiuz
Mesh, bitmap and animator is finalized, but not the material.
Hi,
Would it be possible in future to set *.obj and *.mtl file manually to Loader3D. Would be nice to have that feature. I need it because I want to load all files with a LoaderGroup in my Framework.
Right now I use _loader.parseData(_dto.weapons[0], _parser, assetContext); that ignores the mtl file cause I set AssetLoaderContext.includeDependencies to false.
Question: How can I mark an Issue as "Feature" Request?
Hi,
I think I found some strange behaviors since the latest update following the FP11 beta player.
For the moment, if I change mipmap property of a material to false and I switch it back to true, the Flash player goes down with this error :
Error: Error #3600: No valid program set.
at flash.display3D::Context3D/drawTriangles()
at away3d.materials.passes::MaterialPassBase/render()[D:\Projects\CornFlex\WorldBuilder\build\libs\src\away3d\materials\passes\MaterialPassBase.as:206]
at away3d.materials.passes::DefaultScreenPass/render()[D:\Projects\CornFlex\WorldBuilder\build\libs\src\away3d\materials\passes\DefaultScreenPass.as:436]
at away3d.materials::MaterialBase/renderPass()[D:\Projects\CornFlex\WorldBuilder\build\libs\src\away3d\materials\MaterialBase.as:348]
at away3d.core.render::DefaultRenderer/drawRenderables()[D:\Projects\CornFlex\WorldBuilder\build\libs\src\away3d\core\render\DefaultRenderer.as:108]
at away3d.core.render::DefaultRenderer/draw()[D:\Projects\CornFlex\WorldBuilder\build\libs\src\away3d\core\render\DefaultRenderer.as:48]
at away3d.core.render::RendererBase/executeRender()[D:\Projects\CornFlex\WorldBuilder\build\libs\src\away3d\core\render\RendererBase.as:335]
at away3d.core.render::RendererBase/render()[D:\Projects\CornFlex\WorldBuilder\build\libs\src\away3d\core\render\RendererBase.as:310]
at away3d.containers::View3D/render()[D:\Projects\CornFlex\WorldBuilder\build\libs\src\away3d\containers\View3D.as:357]
I have the same problem with the "repeat" property or when I try to dispose some material (even with dispose(false))
It seems there are some problems with the Bitmap management.
I didn't get that bugs before using the new repo and FP11Beta and I'm running the same project.
Is there anybody already tried this version of BroomStick with the new FP11Beta ?
Thx
Quentin Lengelé
RIA Developer
cornflex.org
The AssetLoader (and Loader3D and AssetLibrary wrappers) should expose some sort of interface and/or events to indicate loading progress. Investigate possible solutions for this and implement the best.
Basic scene no lights/materials
var tri:Trident = new Trident(750, true);
scene.addChild(tri);
[Fault] exception, information=TypeError: Error #1009: Cannot access a property or method of a null object reference.
Fault, dispose() at SubGeometry.as:325
DefaultScreenPass.as line 603 :
Original :
renderable.inverseSceneTransform.copyRawDataTo(_vertexConstantData, _sceneNormalMatrixIndex, false);
Should be:
renderable.inverseSceneTransform.copyRawDataTo(_vertexConstantData, _sceneNormalMatrixIndex, true);
Isn't it ?
AS3 vector based matrix has to be transposed to be used in shader programs.
Move some functionality over to common Animator base-class, and make sure that animations can be composited.
One could argue that this isn't a bug. But it is entirely possible to get SkinnedSubGeometry with a ColorMaterial rather than a BitmapMaterial.
If that is the case, uv data may not be set in the geometry. If you play an animation, a crash happens on line 697:
v0 = _uvs[uint((index1 << 1) + 1)];
_uvs is null.
Main Thread (Suspended: TypeError: Error #1009: Cannot access a property or method of a null object reference.)
The Max3DSParser does not appear to work with multiple materials on a single mesh.
Source files: http://files.envirant.com/test3dsimport.zip
Steps to reproduce:
Expected:
Max3DSParser should support multiple materials per mesh.
Currently there are add and remove methods, but no obvious way to determine if a material has a particular method.
Hi I am using StereoCamera3D as,
_camera = new StereoCamera3D();
_camera.stereoOffset = 45;
_view = new StereoView3D();
_view.antiAlias = 4;
_view.camera = _camera;
_view.stereoEnabled = true;
_view.stereoRenderMethod = new AnaglyphStereoRenderMethod();
addChild(_view);
But it is giving me following error,
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at away3d.stereo::StereoRenderer/getLeftInputTexture()
at away3d.stereo::StereoView3D/render()
at Basic_Stereo/onEnterFrame()
Also,
HoverController is not working with StereoCamera3D.
Thanks
Best Regards
Rajneesh
Make sure that all parsers use finalizeAsset() to properly return all assets that they encounter. Currently, several parsers are probably just reporting the top-level asset (usually a container) as an asset, and ignoring materials, meshes et c.
When mapping a ByteArray to a URL using the AssetLoaderContext, the load will fail silently when the ByteArray does not contain a valid image file (e.g. when it's a pixel list from BitmapData.getPixels()). It needs to be a full file and if not, the ImageParser should fail verbosely.
Make sure error events are dispatched as expected.
Loader3D currently ignores which load an asset is coming from, meaning that if two load operations are started on different loaders and use the same asset library instance for loading, they will both add all assets from both files. Solve this by listening for the asset complete events on the token returned by AssetLibrary.load() instead of directly on the asset library.
Put an option on AssetLoaderContext to override absolute URLs with the dependencyBaseUrl property, so that with base URL "myassets", these are the resolutions that are made:
/abspath/to/file.png -> myassets/abspath/to/file.png
http://example.com/file.png -> myassets/file.png
Maybe have two separate properties for these.
Test: set texture with any test gray color. Create object with texture without DirectionLight and PointLight. Set material
properties mat.ambientColor = 0xffffff;
mat.ambient = 1;
This values should result in 1 to 1 result for shader pass.
Run test and measure displayed by molehill engine texture color. In my test I have got the following result:
Obviously test and displayed color should be equal.
Similar test with directional light, ambient light and the following BitmapMaterial settings for test color 0xffffff:
var dirLight:DirectionalLight = new DirectionalLight(-1, -1, -1);
dirLight.color = 0xffffff;
dirLight.specular = 0.5;
dirLight.diffuse = 1;
var mat:BitmapMaterial = new BitmapMaterial(this._cubeTexture.bitmapData);
mat.lights = [dirLight];
mat.ambientColor = 0xffffff;
mat.ambient = 1;
gives 0xb2b2b2 displayed color (0xffffff was expected for face not lit by directional light and having only ambient contribution).
Another test run with point light and the following settings:
var pointLight:PointLight = new PointLight();
pointLight.color = 0xffffff;
pointLight.specular = 0.5;
pointLight.diffuse = 1;
pointLight.position = new Vector3D(5000, 5000, -5000);
var mat:BitmapMaterial = new BitmapMaterial(this._cubeTexture.bitmapData);
mat.lights = [pointLight];
mat.ambientColor = 0xffffff;
mat.ambient = 0.9;
mat.gloss = 30;
gives even more bizzarre result: faces are not lit according to light position changing light position to
pointLight.position = new Vector3D(-5000, 5000, -5000);
keeps this same faces lit on cube rotating in front of camera set at standard location.
Light on faces is strange as well as faces which should be visible to ambient light only have 0xffffff color, while faces lit by point light have 0xc5c5c5 color (expected is 0.9 * 0xff - for RGB in ambient light and 0xffffff for full point light).
All tests were done with b2d76b2 commit.
The AC3DParser does not support automatic file format detection (when using parseData()) because it does not properly implement the supportsData() method.
Fabrice, please fix this, or provide me with a file format specification/documentation and assign this issue back to me and I will fix it. Cheers!
Seems like SoftShadowTest causes an index out-of-bounds error that needs to be investigated. See post to mailing list here:
http://groups.google.com/group/away3d-dev/browse_thread/thread/aa8591cb5c6a4bd2/3df9c4b123b21ca3?show_docid=3df9c4b123b21ca3
FDT has problems with the word "namespace" being used as the name for a variable. Avoid this by renaming it "ns".
Materials has too many dependencies and are not modular enough to ease the creation of custom materials.
When people is creating custom materials they're likely to be extending DefaultMaterialBase because it has built in useful properties (diffuse\specular\normals\etc are already there, no reason to reimplement them from scratch by extending MaterialBase). Further, they're likely to be creating a custom screenPass, however the screenpass is initialized within the constructor of DefaultMaterialBase and it's private, so it's not accessible from an extending class.
What i'd do in the short run is:
What I'd do in the long run is:
refactor the way materials are designed by using a more modular factory pattern.
I'd prefer materials to have a construction such as
new FactoryMaterial( [ DiffusePassClass, AmbientPassClass, WhateverPassClass ], [ [argForDiffuse], [argForAmbient,argForAmbient2], [argForWhatever] ] )
the FactoryMaterial class is then retrieving the passes instances from a factory which can be relative to the current context3D.
Moreover, the factory should be retrieving the passes instances from a pool.
With this approach a user who want's to create a custom material is not going to extend an existing material but he's just writing the code he needs and he's composing a material with the classes provided by the framework.
Moreover the framework is still able to provide "shortcut" materials to the user by providing "prebuilt" materials with few parameters for a quick use (or for dumb users :)). I mean: BitmapMaterial(bitmapData : BitmapData,etc) should just be extending FactoryMaterial and passing in the constructor exactly the classes it's right now using and inheriting by DefaultMaterialBase.
I hope to have been clear :)
If you need some help I'll gladly help you, just ping me in twitter @pigiuz
The old material library still exists alongside the asset library, and one could argue that it should be merged into the AssetLibrary. Investigate whether this is possible without losing valuable functionality.
If there are no names in an OBJ file, the parser should not invent names but instead use null for the name for all unnamed assets. As the asset is finalized (using finalizeAsset()) ParserBase will assign a generic name by type.
We've created a modified copy of the InteractionTest.as example to show this bug...
package
{
import away3d.containers.View3D;
import away3d.entities.Mesh;
import away3d.events.MouseEvent3D;
import away3d.materials.BitmapMaterial;
import away3d.primitives.Plane;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.Sprite;
import flash.events.Event;
[SWF(width="800", height="450", frameRate="60")]
public class InteractionTest extends Sprite
{
private var _view : View3D;
private var _mesh1 : Plane;
private var _mesh2 : Plane;
private var _flipFlop : Boolean = false;
public function InteractionTest()
{
_view = new View3D();
_view.x = 100;
_view.y = 50;
_view.width = 600;
_view.height = 300;
this.addChild(_view);
addMesh();
this.addEventListener(Event.ENTER_FRAME, handleEnterFrame);
}
private function onMouseOver(event : MouseEvent3D) : void
{
//do nothing
}
private function addMesh():void
{
var bitmapData1 : BitmapData = new BitmapData(512, 512, false, 0xbbbbbb);
bitmapData1.perlinNoise(64, 64, 5, _flipFlop ? 0 : 1, false, true, _flipFlop ? BitmapDataChannel.RED :
BitmapDataChannel.BLUE);
var material1:BitmapMaterial = new BitmapMaterial(bitmapData1);
var mesh:Plane = new Plane(material1, 500, 500, 1, 1);
_view.scene.addChild(mesh);
mesh.mouseEnabled = true;
mesh.addEventListener(MouseEvent3D.CLICK, onMouseClick);
mesh.addEventListener(MouseEvent3D.MOUSE_OVER, onMouseOver);
if(_flipFlop) _mesh1 = mesh;
else _mesh2 = mesh;
}
private function removeMesh():void
{
var mesh:Mesh = _flipFlop ? _mesh1 : _mesh2;
_view.scene.removeChild(mesh);
mesh.dispose(true);
mesh.removeEventListener(MouseEvent3D.CLICK, onMouseClick);
mesh.removeEventListener(MouseEvent3D.MOUSE_OVER, onMouseOver);
if(_flipFlop) _mesh1 = null;
else _mesh2 = null;
}
private function onMouseClick(ev : Event) : void
{
removeMesh();
_flipFlop = ! _flipFlop;
addMesh();
}
private function handleEnterFrame(ev : Event) : void
{
_view.render();
}
}
}
The code does the following:
My initial thought was that the onMouseClick function is being called from HitTestRenderer, while its iterating the scene - and we're modifying that scene in onMouseClick - which would probably invalidate the iteration loop. But it seems like that would be less timing sensitive.
Any thoughts?
-Dave
ps. Thanks go to my coworker Craig for putting this example together.
For some reasons, all animation assets in an AWD file are treated as collisions, given a numeric suffix. Why are they reported as conflicts when there is only one asset? Investigate.
Some objects (transform and pivotPoint) are assigned to the clone as references instead of clones, meaning that changing the transform of the clone will also affect the original, and vice versa. Is this intentional?
Investigate implementing separate COMPLETE events for every asset type, e.g. MATERIAL_COMPLETE, BITMAP_COMPLETE, MESH_COMPLETE et c. This would please good old Fabrice, as it would indeed make loading of simple meshes easier, and shouldn't be too hard to implement.
The AssetLibrary needs to deal with naming collisions, in case a user renames an asset with a name that has already been assigned to another one. Expose this functionality as "strategies" with possible strategies being for example "Throw error" and "Add suffix".
There is new regression introduced by latest commits. 3DS models are not loaded anymore while at revision level:
were loaded correctly. Have not tested with other parsers. There are no errors thrown but number of loaded children stays at 0.
Code used for loading:
Loader3D.enableParser(Max3DSParser);
_loader = new Loader3D();
_loader.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
_loader.addEventListener(LoaderEvent.LOAD_ERROR, onLoadError);
_loader.parseData(model3DS, null, new AssetLoaderContext(false));
_loader.scale(50);
private function onResourceComplete(ev : LoaderEvent) : void
{
var mesh : Mesh;
var len : uint = _loader.numChildren;
var material : ColorMaterial = new ColorMaterial(0x777777);
material.ambientColor = 0xffffff;
for (var i : uint = 0; i < len; ++i) {
mesh = Mesh(_loader.getChildAt(i));
mesh.material = material;
mesh.geometry.subGeometries[0].autoDeriveVertexNormals = true;
mesh.geometry.subGeometries[0].autoDeriveVertexTangents = true;
this._view.scene.addChild(mesh);
}
}
Create an AssetLibrary iterator, that can optionally filter by type, e.g.:
var it : LibraryIterator = AssetLibrary.getIterator(AssetType.MESH);
var mesh : Mesh;
while (mesh = Mesh(it.next()) {
// Do something with mesh
}
It should reflect the behavior of the mouseChildren property in the standard flash display list.
Currently, you have to recursively loop through the children of a container and set the mouseEnabled property.
Use protected in order to let us extend the framework.
I encountered a high difficulty in creating custom materials because all the properties I needed were scoped as private instead of protected. Please use protected!!
If you really don't want people to be playing with the framework's internal gears my suggestion is to scope them as part of the custom namespace "arcane" or to create a new custom namespace for each specific area of the framework (ex: "arcane_materials", "arcane_geom", etc)
The same is suggested for "final"... I don't think any class should be marked as final in an alpha version
My fast fix for the AWD1Parser was (as with the other parsers) to just finalizeAsset() the top-level asset, which is a container. This means that the container is the only asset to be reported back from the parser. This needs to be fixed so that all IAsset classes (materials, meshes et c) are finalized and hence returned to the library.
[Event(name="resourceRetrieved",type="away3d.events.away3d.events.LoaderEvent")]
Hi! Noticed that mesh's material name contains only "Obj0" instead of real material name, as "coolSong".
I'm trying to get the materials names with this code:
//...
Loader3D.enableParser(OBJParser);
_loader = new Loader3D();
_loader.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
_loader.load(new URLRequest('model.obj'));
//...
private function onResourceComplete(ev: LoaderEvent) : void
{
//...
var len: uint = _loader.numChildren;
for (var i: uint = 0; i < len; i++)
{
//...
mesh = Mesh(_loader.getChildAt(i));
trace(mesh.material.name); // traces "Obj0", "Obj1", etc
//...
}
//...
}
I debugged names resolving process a bit and figured out some strange behavior in the OBJParser:
In the away3d.loaders.parsers.OBJParser:
https://github.com/away3d/away3d-core-broomstick/blob/master/src/away3d/loaders/parsers/OBJParser.as
In the method translate(), this code:
if(groups[g].materialID != "")
{
bmMaterial.name = groups[g].materialID+"~"+mesh.name;
}
else
{
bmMaterial.name = _lastMtlID+"~"+mesh.name;
}
generates material names like "coolSong~Obj1".
And after it, at the applyMaterial() method:
//...
decomposeID = mesh.material.name.split("~");
//...
mesh.material.name = decomposeID[1];
Name replaced with it's second part after a "~" char and looks after it like "Obj1"
So, name after translate() is looks like: "coolSongObj1";" char - decomposeID[1]);
And after applyMaterial() it changes for "Obj1" (because used part after the "
But in this case material name is erased at all, leaving just the mesh name I guess =(
Why not to use the decomposeID[0]
instead of decomposeID[1]
to leave the material name only (erasing the mesh name) or leave the whole name "coolSong~Obj1"?
Details and example code here:
https://groups.google.com/forum/#!topic/away3d/NoOLB-2WXy4
"zbuffer with alpha question" thread on away3d groups.
The Max3DSParser assigns a bitmap material to all meshes by default, regardless of whether there is a material in the file. This means that even meshes that don't have UV maps will be given a BitmapMaterial, causing a crash after load. I would suggest using a ColorMaterial by default instead, perhaps in one of the Away3D colors. ;)
Code I am working on right now does require quite a bit of object movement control and as this seems to be quite basic feature of any object in 3D world it would be very handy to have 3D vectors describing the following object movement properties:
speed : Vector3D
acceleration : Vector3D
rotationSpeed : Vector3D
roatationAcceleration : Vector3D
Many other engines support that set of properties. Obviously it's easy to subclass something you want to use but since it is very basic feature for any moving object it would be convenient to have it implemented globally at root level of class tree.
All parsers should use a consistent naming scheme for unnamed assets. This can be solved by setting names for unnamed assets in ParserBase.finalizeAsset(), but requires that the concrete parser doesn't invent a name itself.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.