C++ OpenGL ES espectador en C# (4 / 8 paso)

Paso 4: Crear la capa de soporte de plataformas Windows

Ahora necesitamos agregar clase de ayudante de OpenGLES de Microsoft para el proyecto del puente C++ compartidas. Así que por favor sólo agregue una clase denominada OpenGLES a ese proyecto.

El encabezado debe contener:

 #pragma once#include <EGL/egl.h> 
 class OpenGLES { public: OpenGLES(); ~OpenGLES(); 
 EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize); void DestroySurface(const EGLSurface surface); void MakeCurrent(const EGLSurface surface); EGLBoolean SwapBuffers(const EGLSurface surface); void Reset(); 
 private: void Initialize(); void Cleanup(); 
 private: EGLDisplay mEglDisplay; EGLContext mEglContext; EGLConfig mEglConfig; }; 

Y el archivo cpp debe contener:

 #include "OpenGLES.h"#include <concrt.h> #include <EGL/egl.h> #include <EGL/eglext.h> #include <EGL/eglplatform.h> #include <angle_windowsstore.h> 
 using namespace Platform; using namespace Windows::UI::Xaml::Controls; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; 
OpenGLES::OpenGLES(): mEglConfig(nullptr), mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) {Initialize(); OpenGLES::OpenGLES() : mEglConfig(nullptr), mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) { Initialize(); } 
OpenGLES::~OpenGLES() {Cleanup(); OpenGLES::~OpenGLES() { Cleanup(); } 
 void OpenGLES::Initialize() { const EGLint configAttributes[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8, EGL_NONE }; 
 const EGLint contextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 
 const EGLint defaultDisplayAttributes[] = { // These are the default display attributes, used to request ANGLE's D3D11 renderer. // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+. EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 
 // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices. // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it. EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, 
 // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended. // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement. EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; 
 const EGLint fl9_3DisplayAttributes[] = { // These can be used to request ANGLE's D3D11 renderer, with D3D11 Feature Level 9_3. // These attributes are used if the call to eglInitialize fails with the default display attributes. EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9, EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3, EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; 
 const EGLint warpDisplayAttributes[] = { // These attributes can be used to request D3D11 WARP. // They are used if eglInitialize fails with both the default display attributes and the 9_3 display attributes. EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; 
 EGLConfig config = NULL; 
eglGetPlatformDisplayEXT es una alternativa a eglGetDisplay. Nos permite pasar en atributos de pantalla, permite configurar D3D11. PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast (eglGetProcAddress("eglGetPlatformDisplayEXT")); Si (! eglGetPlatformDisplayEXT) {throw Exception::CreateException (E_FAIL, L "No se pudo obtener la función eglGetPlatformDisplayEXT"); // eglGetPlatformDisplayEXT is an alternative to eglGetDisplay. It allows us to pass in display attributes, used to configure D3D11. PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast (eglGetProcAddress("eglGetPlatformDisplayEXT")); if (!eglGetPlatformDisplayEXT) { throw Exception::CreateException(E_FAIL, L"Failed to get function eglGetPlatformDisplayEXT"); } 
 // // To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize, with varying // parameters passed to eglGetPlatformDisplayEXT: // 1) The first calls uses "defaultDisplayAttributes" as a parameter. This corresponds to D3D11 Feature Level 10_0+. // 2) If eglInitialize fails for step 1 (e.g. because 10_0+ isn't supported by the default GPU), then we try again // using "fl9_3DisplayAttributes". This corresponds to D3D11 Feature Level 9_3. // 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again // using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer. // // Note: On Windows Phone, we #ifdef out the first set of calls to eglPlatformDisplayEXT and eglInitialize. // Windows Phones devices only support D3D11 Feature Level 9_3, but the Windows Phone emulator supports 11_0+. // We use this #ifdef to limit the Phone emulator to Feature Level 9_3, making it behave more like // real Windows Phone devices. // If you wish to test Feature Level 10_0+ in the Windows Phone emulator then you should remove this #ifdef. // 
#if (WINAPI_FAMILY! = WINAPI_FAMILY_PHONE_APP) / / esto intenta inicializar EGL a nivel de función de D3D11 10_0 +. Véase comentario para más detalles. mEglDisplay = eglGetPlatformDisplayEXT (EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); Si (mEglDisplay == EGL_NO_DISPLAY) {throw Exception::CreateException (E_FAIL, L "No se pudo obtener pantalla EGL"); #if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details. mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); if (mEglDisplay == EGL_NO_DISPLAY) { throw Exception::CreateException(E_FAIL, L"Failed to get EGL display"); } 
Si (eglInitialize (mEglDisplay, NULL, NULL) == EGL_FALSE) if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE) #endif { // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on Windows Phone, or certain Windows tablets). mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); if (mEglDisplay == EGL_NO_DISPLAY) { throw Exception::CreateException(E_FAIL, L"Failed to get EGL display"); } {/ / Esto intenta inicializar EGL a nivel de función de D3D11 9_3, si 10_0 + no está disponible (por ejemplo, en Windows Phone, o ciertos comprimidos de Windows). mEglDisplay = eglGetPlatformDisplayEXT (EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); if (mEglDisplay == EGL_NO_DISPLAY) {throw Exception::CreateException (E_FAIL, L "No se pudo obtener pantalla EGL"); if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE) { // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU (e.g. on Surface RT). mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes); if (mEglDisplay == EGL_NO_DISPLAY) { throw Exception::CreateException(E_FAIL, L"Failed to get EGL display"); } 
Si (eglInitialize (mEglDisplay, NULL, NULL) == EGL_FALSE) {/ / esto inicializa EGL a nivel de función de D3D11 11_0 en WARP, si 9_3 + está disponible por defecto GPU (e.g. en Surface RT). mEglDisplay = eglGetPlatformDisplayEXT (EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes); if (mEglDisplay == EGL_NO_DISPLAY) {throw Exception::CreateException (E_FAIL, L "No se pudo obtener pantalla EGL"); if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE) { // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. throw Exception::CreateException(E_FAIL, L"Failed to initialize EGL"); } } } 
Si (eglInitialize (mEglDisplay, NULL, NULL) == EGL_FALSE) {/ / si todas las llamadas a eglInitialize volvieron EGL_FALSE entonces se ha producido un error. tiro Exception::CreateException (E_FAIL, L "No se pudo inicializar EGL"); EGLint numConfigs = 0; if ((eglChooseConfig(mEglDisplay, configAttributes, &mEglConfig, 1, &numConfigs) == EGL_FALSE) || (numConfigs == 0)) { throw Exception::CreateException(E_FAIL, L"Failed to choose first EGLConfig"); } } mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, contextAttributes); if (mEglContext == EGL_NO_CONTEXT) { throw Exception::CreateException(E_FAIL, L"Failed to create EGL context"); } } 
EGLint numConfigs = 0; Si ((eglChooseConfig (mEglDisplay, configAttributes, & mEglConfig, 1 & numConfigs) == EGL_FALSE) || (numConfigs == 0)) {throw Exception::CreateException (E_FAIL, L "No se elige primer EGLConfig"); void OpenGLES::Cleanup() { if (mEglDisplay != EGL_NO_DISPLAY && mEglContext != EGL_NO_CONTEXT) { eglDestroyContext(mEglDisplay, mEglContext); mEglContext = EGL_NO_CONTEXT; } 
mEglContext = eglCreateContext (mEglDisplay, mEglConfig, EGL_NO_CONTEXT, contextAttributes); Si (mEglContext == EGL_NO_CONTEXT) {throw Exception::CreateException (E_FAIL, L "No se pudo crear contexto EGL"); if (mEglDisplay != EGL_NO_DISPLAY) { eglTerminate(mEglDisplay); mEglDisplay = EGL_NO_DISPLAY; } } 
void OpenGLES::Cleanup() {si (mEglDisplay! = EGL_NO_DISPLAY & & mEglContext! = EGL_NO_CONTEXT) {eglDestroyContext (mEglDisplay, mEglContext); mEglContext = EGL_NO_CONTEXT; void OpenGLES::Reset() { Cleanup(); Initialize(); } 
Si (mEglDisplay! = EGL_NO_DISPLAY) {eglTerminate(mEglDisplay); mEglDisplay = EGL_NO_DISPLAY; EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize) { if (!panel) { throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid"); } 
void OpenGLES::Reset() {Cleanup(); Initialize(); EGLSurface surface = EGL_NO_SURFACE; 
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize) {si (! panel) {throw Exception::CreateException (E_INVALIDARG, L «SwapChainPanel parámetro no es válido»); const EGLint surfaceAttributes[] = { // EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is part of the same optimization as EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER (see above). // If you have compilation issues with it then please update your Visual Studio templates. EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE, EGL_NONE }; 
 // Create a PropertySet and initialize with the EGLNativeWindowType. PropertySet^ surfaceCreationProperties = ref new PropertySet(); surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), panel); 
 // If a render surface size is specified, add it to the surface creation properties if (renderSurfaceSize != nullptr) { surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize)); } 
 surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast(surfaceCreationProperties), surfaceAttributes); if (surface == EGL_NO_SURFACE) { throw Exception::CreateException(E_FAIL, L"Failed to create EGL surface"); } 
Si se especifica un tamaño de la superficie de procesamiento, agregar a las propiedades de creación superficie si (renderSurfaceSize! = nullptr) {surfaceCreationProperties -> Insertar (ref String(EGLRenderSurfaceSizeProperty) nuevo, PropertyValue::CreateSize(*renderSurfaceSize)); return surface; } 
superficie = eglCreateWindowSurface (mEglDisplay, mEglConfig, reinterpret_cast(surfaceCreationProperties), surfaceAttributes); Si (superficie == EGL_NO_SURFACE) {throw Exception::CreateException (E_FAIL, L "No se pudo crear superficie EGL"); void OpenGLES::DestroySurface(const EGLSurface surface) { if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE) { eglDestroySurface(mEglDisplay, surface); } } 
volver a la superficie; void OpenGLES::MakeCurrent(const EGLSurface surface) { if (eglMakeCurrent(mEglDisplay, surface, surface, mEglContext) == EGL_FALSE) { throw Exception::CreateException(E_FAIL, L"Failed to make EGLSurface current"); } } 
void OpenGLES::DestroySurface (const EGLSurface superficie) {si (mEglDisplay! = EGL_NO_DISPLAY & & superficie! = EGL_NO_SURFACE) {eglDestroySurface (mEglDisplay, superficie); EGLBoolean OpenGLES::SwapBuffers(const EGLSurface surface) { return (eglSwapBuffers(mEglDisplay, surface)); } 
void OpenGLES::MakeCurrent (const EGLSurface superficie) {si (eglMakeCurrent (mEglDisplay, superficie, superficie, mEglContext) == EGL_FALSE) {throw Exception::CreateException (E_FAIL, L «No EGLSurface actual»); #if WIN_STORE 
EGLBoolean OpenGLES::SwapBuffers(const EGLSurface surface) {return (eglSwapBuffers (mEglDisplay, superficie)); #define MAINNAMESPACE CppGLESBridge_Win 

Una vez más, esto es tomado de la plantilla de ángulo y tiene trabajo necesita probablemente no le conciernen. Otra vez prueba a ver si todavía se puede compilar.

OK ahora para el CX (versión de runtime C++ de Microsoft extensiones de C++ o lo que se llama) / (la versión de C++ con la sintaxis muy divertida) contenedor que nos proporciona una interfaz de C# sin problemas. Por ahora usaremos una versión modificada del código de la Página principal que se encuentra en la plantilla del ángulo. Como esta página ya es realidad una C# objetos, tenemos la ruta de los eventos de C# a C++. El resto del código puede guardarse en el C++ en cuanto a mantener las cosas simples.

Ahora crear una clase en la clase de puente compartido y lo llaman GLESSurface. La clase tendrá que ser en un espacio de nombres con el mismo nombre que su proyecto porque de lo contrario obtendrá errores al intentar compilar la aplicación C#. El problema es que este espacio de nombres diferente para los proyectos de la tienda de Windows y Windows Phone. Para solucionar esto tenemos que añadir algunas directivas de preprocesador. Para el proyecto de la tienda he añadido "WIN_STORE" y para el PM uno "WIN_PHONE". Tal vez ya hay algunos predeterminados los que trabajan pero no podía encontrarla y acabo de ir con estos. Con estos entonces podría utilizar lo siguiente en el archivo de encabezado para definir el espacio de nombres necesaria:

 #else if WIN_PHONE 
 #define MAINNAMESPACE CppGLESBridge_WP 
 #endif 
 using Windows.UI.Core; 
 using CppGLESBridge_Win; 

Usted necesitará cambiar aquellos a lo que llaman sus proyectos. Mina se llaman "CppGLESBridge.Win" y "CppGLESBride.WP". Usted debe han sido capaces de ver qué espacio de nombres necesaria en los archivos de Class1 predeterminada. También puede utilizar algo como esto por todas partes en el código de C++ donde necesita hacer algo ligeramente diferente para WP y almacén de Victoria.

Ahora trato de compilar para ver si todo funciona. Esto es necesario porque el componente de tiempo de ejecución necesita ser compilado antes de Intellisense puede comenzar a registrar al cambiar a C#.

Si todo ha ido bien hasta ahora entonces estarás muy cerca de ver algo ahora pero todavía no estamos allí. Sólo llegaremos a Xamarin.Forms al final del tutorial. Por ahora sólo queremos ver un cubo hilado color en todas las plataformas. Así que ir a archivos de MainPage.xaml para ganar y WP y añadir que un SwapChainPanel llamado algo así como "swapPanel" como se aprecia en las imágenes.

Ahora usted necesita abrir el MainPage.xaml.cs para cada proyecto. Agregue las siguientes instrucciones using:

 gs = new GLESSurface(swapPanel); 
 CoreWindow window = Window.Current.CoreWindow; 

El CppGLESBridge_Win es para la tienda de Victoria y luego debe usar CppGLESBridge_WP para WP. Si te fuiste con otro nombre entonces a adaptar estos adecuadamente. A continuación, cree un objeto privado de GLESSurface en ambos proyectos. Nos enrutar los eventos para este objeto. Entonces usted necesita crear este objeto y conectar los eventos de C# es necesarios para los controladores de C++. Desea que su método de MainPage() para eventualmente contener además de lo que ya estaba allí:

 window.VisibilityChanged += (CoreWindow sender, VisibilityChangedEventArgs args) => { gs.OnVisibilityChanged(sender, args); }; 
 swapPanel.SizeChanged += (object sender, SizeChangedEventArgs e) => { gs.OnSwapChainPanelSizeChanged(sender, e); }; 
 this.Loaded += (object sender, RoutedEventArgs e) => { gs.OnPageLoaded(sender, e); }; 
 using System.Runtime.InteropServices;using Android.Opengl; 
 namespace CppGLESXamarin.Android { class MyGLRenderer : Java.Lang.Object, GLSurfaceView.IRenderer { [DllImport("libAndroidGLESBridge.so")] public static extern void on_surface_created(); 

Hay imágenes de los archivos de Windows Store y final de Windows Phone.

Si compilar y ejecutan tus proyectos ahora debería ver un cubo hilado.

Artículos Relacionados

Principiantes guían de OpenGL: construir su propio software de CAD

Principiantes guían de OpenGL: construir su propio software de CAD

Mi carné de estudiante de Autodesk Maya expirado recientemente. Así que hice lo que cualquiera haría, construir mi propio 3D CAD software (cuidado con Autodesk).Así que empecé a escribir mi aplicación en C++ usando OpenGL, SDL y en aproximadamente un
D & D Espectador monstruo Fondue

D & D Espectador monstruo Fondue

Gran convite para su favorito Dungeon Master o LARP! Que sabía mini Beholders gusto como ' Smores!Beholders, también conocidos como "esferas de muchos ojos" o "ojo de los tiranos," son uno de los monstruos originales de Dungeons and Dr
Cupcakes de espectador

Cupcakes de espectador

estas magdalenas son el tratar de geek perfecta para tu sesión de Dungeons & Dragons, Magic el encuentro juego, o cualquier otra ocasión cuando un cupcake normal solo no.  Comen rápidamente antes de que su rayo Anti-masticar le afecta!Paso 1: fuentes
Gracias 1 500 los espectadores!

Gracias 1 500 los espectadores!

Paso 1: ¡ gracias! quiero decir gracias por mirar mis proyectos y realmente lo apreciamos! Por seguir viendo!
Peligro ratón Mini personaje espectadores de pie (con pegatinas)

Peligro ratón Mini personaje espectadores de pie (con pegatinas)

Mello, conseguí un libro de la etiqueta engomada de DangerMouse y así pongo las pegatinas de repuesto a utilizar haciendo estos mini transportines con pegamento caliente y cartón! ¡ Disfrute!Paso 1: fuentes dePistola de pegamento calientePegatinas o
Imprimir fotografía 3D

Imprimir fotografía 3D

impresiones de la impresora 3d en nuestra oficina (un Objet Connex500) con un material blanco semitransparente y rígido que puede utilizarse para crear estas impresiones fotográficas blanco y negro únicas.  Estas impresiones pueden ser indescifrables
Prisma reflector

Prisma reflector

Este sistema de pantalla utiliza una técnica que se refiere a menudo como fantasma de la pimienta. Fue inventado primero por Giambattista della Porta en 1584 y se ha utilizado comúnmente en el teatro. Algunos de sus usos famosos incluyen rendimiento
RECETA elegante y porción de SALSA VERDE

RECETA elegante y porción de SALSA VERDE

Hola queridos visitantes de mi página y los espectadores de mi canal de YouTube!Hoy, quiero presentarles a una ensalada muy popular entre las personas con origen Latino! Hoy en día se considera también una de las ensaladas más preferidas en los Estad
Lámpara de pie hecha de acrílico

Lámpara de pie hecha de acrílico

ProclamaciónSi tenga algún problema o atascarse en cualquier punto dentro del instructivo (especialmente en la imagen de sección de procesamiento o en cualquier parte) apenas sienta libre de enviarme un mensaje de Instructable o un correo electrónico
10 Hacks de la vida con el PVC #13

10 Hacks de la vida con el PVC #13

10 Hacks de la vida con el PVC #13[Ver VIDEO]Aquí le damos la 13ª edición a nuestra serie de "10 Hacks de la vida con el PVC". Construimos y probamos estos proyectos con éxito. Espero que usted puede beneficiarse de algunos de estos hacks de vid
10 Hacks de la vida con el PVC #11

10 Hacks de la vida con el PVC #11

10 Hacks de la vida con el PVC #11[VER VIDEO]Aquí es la 11ª Edición de nuestra serie "10 Hacks de la vida con el PVC". Construimos y probamos estos proyectos con éxito. Espero que usted puede beneficiarse de algunos de estos hacks de vida impres
PRIMAVERA / verano guirnalda de la flor del arco iris de artículos reciclados

PRIMAVERA / verano guirnalda de la flor del arco iris de artículos reciclados

Hola queridos visitantes de mi página y los espectadores de mi canal de YouTube! Hoy quiero mostrarte cómo ahorrar dinero y ciclo de algunos de los productos para el hogar que todo el mundo le gusta tirar y hacer nuestro planeta más sucio! Usted pued
Cohete de agua en $5

Cohete de agua en $5

esto es un cohete de agua fresca que he hecho de todos los materiales de desguace. Se trata de un cohete de agua de muy alta presión y cualquier persona puede construir dentro de $5.Also espectadores, esta es mi entrada para el hacer volar concurso e
Simplista no siempre es aburrido

Simplista no siempre es aburrido

Simple, sin embargo, toneladas de diversión y una configuración fácil para todas las edades!El razonamiento detrás de nuestro trabajo es que queríamos algo para mover con poca o ninguna ayuda del espectador, que se siguen para una buena cantidad de t