text:
(feel free to skip)
I remember discussing this a long time ago in the oculus forums, back when the linux version of the oculus SDK was doing absurdities such as relying on Xinerama to detect and use the oculus display. Setting up the rift display as an extension of the desktop, is wrought with peril and woe. Thankfully, the X window system is awesome, and used to deal with such diverse multi-display contraptions, back when burly men programmed computers made of pumps, grease, and steel… true story.
So anyway, the whole hoop-jumping circus the oculus runtime tries to set up on ms-winblows for "direct access" to the rift, using grotesque custom monitor and display drivers, is really easy to do under X; it's built into the system since its inception, and it's called a "Screen".
It goes like this: each X server is called a "Display", and each Display has one or more Screens. Before the advent of runtime-reconfigurable X servers, we had to write a configuration file (/etc/X11/xorg.conf or further back /etc/X11/XF86Config) which specified (among other things):
Once set up this way, the configuration couldn't change without restarting the X server, and each screen would be completely separate; the mouse cursor would move between screens (according to the spatial layout specified in the ServerLayout), but windows belonged to a specific screen, and couldn't move between them. Rigid, but simple and extremely clear.
Nowadays of course, most multi-monitor setups use the XR&R (xrandr) extension to add and remove "outputs" on a single X screen dynamically, or the equivalent nvidia proprietary counterpart called TwinView. This approach extends a single desktop area across multiple monitors, which is awesome for regular monitors, but really horrible when it comes to peculiar devices such as the rift.
The proper way to do it, is to set up the rift as a separate X screen. To do this, you just need to create an xorg.conf file under /etc/X11 with something like this:
Section "ServerLayout" Identifier "default" Screen 0 "scr_main" 0 0 Screen 1 "scr_rift" Below "scr_main" # could be RightOf, LeftOf, etc EndSection Section "Monitor" Identifier "mon_dell" VendorName "DELL" ModelName "DELL U2412M" EndSection Section "Monitor" Identifier "mon_rift" VendorName "Unknown" ModelName "OVR Rift DK2" EndSection Section "Device" Identifier "dev_main" Driver "nvidia" VendorName "NVIDIA Corporation" BoardName "GeForce GTX 650 Ti" BusID "PCI:1:0:0" Screen 0 EndSection Section "Device" Identifier "dev_rift" Driver "nvidia" VendorName "NVIDIA Corporation" BoardName "GeForce GTX 650 Ti" BusID "PCI:1:0:0" Screen 1 EndSection Section "Screen" Identifier "scr_main" Device "dev_main" Monitor "mon_dell" DefaultDepth 24 SubSection "Display" Depth 24 EndSubSection EndSection Section "Screen" Identifier "scr_rift" Device "dev_rift" Monitor "mon_rift" DefaultDepth 24 SubSection "Display" Depth 24 EndSubSection EndSection
Of course if you use the proprietary nvidia drivers, you may also run nvidia-settings, configure your screens from the GUI, and press a button to create the xorg.conf file automatically (which will take effect when you restart your X server).
Note that under "configuration" for the currently selected rift screen, it says "X screen 1". Initially this combo box will have "X screen 0" selected; you need to click on it and select "New X screen" to create a separate screen for the rift.
If the rift is set up as a separate X screen, you don't have to fiddle with moving windows around to place them at the right position of the desktop to show up in the rift, and pray to odin that they stay there when you switch to fullscreen. Just instruct the program to use the correct screen by setting the DISPLAY environment variable, and it can't escape if its life depended on it (well it could ignore the DISPLAY env var and open a window elsewhere, but that takes conscious effort to do).
So for instance to run my oculus2 test program on the rift, I just have to do something like:
$ DISPLAY=:0.1 ./oculus2
The first number just after the colon is the display (X server) we wish to run the program on, followed by the screen number after the dot (our main monitor would be :0.0, or just :0).
Sometimes it's very useful to see what's going on in the rift display, without having to put it on and off all the time, especially when hacking VR programs. For this reason I wrote a small shell script which starts a vnc server on the rift screen, and a vnc viewer on the main screen:
#!/bin/sh x11vnc -display :0.1 -scale 0.5 -rotate +90 \ -localhost -nopw -norc -timeout 1 \ -q -viewonly -once -bg && \ vncviewer localhost
I rotated the vnc output by 90 degrees because the rift has a portrait display and all VR apps are sideways to compensate. I also scaled it by 50%, and instructed the vnc server to shut down when the viewer disconnects.
Feel free to use it, I found it very handy.
I just finished watching the video of the Khronos GDC talk on Vulkan, and the corresponding slides, and I decided to share my initial thoughts on the new API, mostly in an attempt to consolidate them.
For those who missed the announcements of the last couple of days, Vulkan is supposed to be the successor to OpenGL, previously referred to as: glNext. The idea is to provide a low level API, basically a thin abstraction over the GPU hardware, along the lines of Apple Metal and AMD Mantle (as far as I've heard at least; I have no personal experience with either of the them).
I've been back and forth for a while, on whether I like or dislike this development. Until I realized that all my objections where centered around the idea that Vulkan is going to replace OpenGL. And by that, I mean that somehow everyone using OpenGL today, would switch over to Vulkan, something which is clearly not true. It is certainly talked about as a replacement for OpenGL, however in my opinion, it both is and isn't. Let me explain…
OpenGL, from its inception, had a multiple personality disorder. This is clear just by reading the introductory chapter of the OpenGL specification document, which requires 4 consecutive sections, looking at OpenGL from different perspectives over the span of 3 pages, to attempt to define what OpenGL is:
For me, and my daily hacking, OpenGL plays two distinct roles:
Based on that, it is now clear to me that Vulkan is indeed a very good replacement for the first use case, but completely unsuitable for the second. That's why I think that Vulkan is not really a replacement of OpenGL. Vulkan and OpenGL can, and should coexist!
Vulkan looks like a perfect target for the reusable frameworks and engines. It provides some great opportunities for optimizations. I'm particularly excited about finally being able to multi-thread rendering code, without jumping through hoops (and performance bottlenecks) to serialize all API interactions through "the context thread". I love the idea of having the API only deal with a concise intermediate representation of the shading language, which facilitates experimentation with new shading language frontends, off-line shader compilers, and avoids having to work around multiple vendors' parser bugs and idiosyncrasies. I also like the idea of being able to manage the allocation and use of GPU resources, and the flow of data.
But, at the same time, I want the ease of use of OpenGL for my day to day hacks and experiments. I want immediate mode, matrix stacks, and the option of not having to care whether a texture or vertex buffer is currently backed by GPU memory or not.
I'll go one step further, and this is really the gist of my thoughts on the matter: Not only should there be an OpenGL implementation over Vulkan, to use for experimental programs and one-off hacks, but ideally both should be seamlessly interoperable within the same program. Think of how powerful it would be to be able to start with an OpenGL prototype, and then go to the metal with Vulkan wherever you want to optimize! This way, to put it in 90s terms: Vulkan could be the assembly language of OpenGL.
Anyway, this pretty much sums up my initial thoughts on the Vulkan announcement. It's still quite early and Vulkan itself is still in flux, so I guess we'll have to wait and see how the whole thing turns out. But one thing is clear to me: Vulkan is very exciting, but OpenGL isn't going to go away any time soon.
While none of the above solutions is without some merit in particular cases, I strongly believe that there's no faster and simpler way to build your project, than writing a small makefile. And in order to dispel the fear, I decided to write a tutorial about how to write simple, practical makefiles, for your programs.
The article is too big and too … structured, for my idea of what a blog post should be, so I'm hosting it on my web site along with some of my previous articles instead.
So anyway here it is, let me know if you find it useful: Practical makefiles, by example.
Feel free to use the comments section in this post for any feedback, or send me an email if you prefer.
Btw, I used reStructuredText, and the docutils translators for this. So there's also a PDF version, produced through the rst2latex translator. It's not as good as it could have been if I wrote it directly in LaTeX, but I suppose it's serviceable if you prefer a printable off-line version.
Android applications are strange beasts. Even though under the hood it's basically a UNIX system using Linux as its kernel, there are other layers between (native) android apps and the bare system, that some things are bound to fall through the cracks.
When developing android apps, one generally doesn't login to the actual device to compile and execute the program; instead a cross-compiler is provided by google, along with a series of tools to package, install, and execute the app. The degrees of separation from the actual controlling terminal of the application, make it harder to just print debugging messages to the stdout and stderr streams and watch the output like one could do while hacking a regular program. For this reason, the android NDK provides a set of logging functions, which append the messages to a global log buffer. The log buffer can be viewed and followed remotely, from the development machine, over USB, by using the "adb logcat" tool.
This is all well and good, but if you're porting a program which prints a lot of messages to stdout/stderr, or if you just like the convenience of using the standard printf/cout/etc functions, instead of funny looking stuff like
__android_log_print(), you might wonder if there is a way to just use the standard I/O streams instead, right? Well so did I, and guess what… this is still UNIX so the answer is of course you can!
The simplest solution to this problem would be if we could just redirect stdout and stderr to wherever these
__android_log_whatever functions are writting their messages. This will obviously be either a socket or a pipe of some sort, but alas it's not exposed in any way through the NDK APIs. We could figure out where it goes if we where to dig through JNI calls and Java classes in the intermediate layers, but a change in a future version of android or its SDKs, might break our code if we use such undocumented ways to log messages. I'd rather not go through all this trouble, and introduce incompatibilities in the process.
An easier, albeit slightly more convoluted way to attack this, which I ended up using, is to create a pipe, redirect stdout and stderr to the write end of the pipe, and start a logging thread which just blocks reading the other end of that pipe, and calls the NDK log functions to log whatever is coming through.
Here's a short snippet from my android logger demonstrating how to set that up:
static int pfd[2]; static pthread_t thr; static const char *tag = "myapp"; int start_logger(const char *app_name) { tag = app_name; /* make stdout line-buffered and stderr unbuffered */ setvbuf(stdout, 0, _IOLBF, 0); setvbuf(stderr, 0, _IONBF, 0); /* create the pipe and redirect stdout and stderr */ pipe(pfd); dup2(pfd[1], 1); dup2(pfd[1], 2); /* spawn the logging thread */ if(pthread_create(&thr, 0, thread_func, 0) == -1) return -1; pthread_detach(thr); return 0; } static void *thread_func(void*) { ssize_t rdsz; char buf[128]; while((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) { if(buf[rdsz - 1] == '\n') --rdsz; buf[rdsz] = 0; /* add null-terminator */ __android_log_write(ANDROID_LOG_DEBUG, tag, buf); } return 0; }
For those not familliar with UNIX system programming, redirection of file descriptor is done by closing the fd in question and duplicating another existing file descriptor in its place (with dup or dup2). Also you'll notice in the logging thread I'm removing the trailing newline if it's there. That is because
__android_log_write will append its own newline to any messages we log through it.
Anyway, by calling start_logger somewhere at the start of android_main, anything printed from that point onwards to stdout/stderr will end up in the android log. Feel free to use it in your programs if you find it useful.
Edit2: Updated the code to work with LibOVR 0.5.0.1, but unfortunately they removed the handy function which I was using to disable the obnoxious "health and safety warning". See the oculus developer guide on how to disable it system-wide instead.
I've been hacking with my new Oculus Rift DK2 on and off for the past couple of weeks now. I won't go into how awesome it is, or how VR is going to change the world, and save the universe or whatever; everybody who cares, knows everything about it by now. I'll just share my experiences so far in programming the damn thing, and post a very simple OpenGL test program I wrote last week to try it out, that might serve as a baseline.
It's the early days of DK2 really, and it definitely shows. There's a huge list of issues to be ironed out software-side by Oculus, and DK2 development is a bit of a pain in the ass at the moment.
First and foremost, there's no GNU/Linux support in the oculus driver/SDK (current version 0.4.2) yet. That's what we get for relying on proprietary crap, so there's no point in whining about it. We should bite the bullet and write a free software replacement or shut the fuck up really. OpenHMD looks like a good start, although it still only does rotation tracking, and doesn't utilize the IR camera to calculate the head position. Haven't tried it yet because I'm lazy, but using and improving it is the only future-proof way to go really. For now I'm stuck on my old nemesis: windows, due to the oculus sdk.
Second issue, is that even on windows, the focus up to now is really Direct3D 11 support. The oculus driver does a weird stunt to let programs output to the rift display, without having it act as another monitor that shows part of the desktop and confuse users. That mode is called "direct-to-rift" and it really doesn't work at all for OpenGL programs at the moment. As I don't have any intention of hacking Direct3D code again in my life (I've had my fill in the past), I'm stuck in extended desktop mode, and I'm also missing a couple of features that are still D3D-only in the SDK. Hopefully this too will be fixed soon. Again, proprietary software problems, so not much that can be done about it other than begging oculus to fix it in the next release.
There are other, relatively minor issues, like a really anoying and completely ridiculus health and safety warning that pops up every time an application initializes the oculus rift, but I'll not dwell on how stupid that is, since it thankfully can be disabled by calling a private internal SDK function (see example code at the end).
So anyway, onwards to the SDK and how to program for the rift. One huge improvement since the last time I did anything for the Oculus Rift DK1 with SDK 0.2.x, is the new C API they've added. The old ad-hoc set of C++ classes was really a joke, and even though the new API isn't exactly what I'd call elegant, it's definitely much more usable.
With the old SDK, one would have to render each eye's view to a texture using the projection matrix and orientation quaternions supplied by the SDK. Then draw both images onto the display itself taking care to pre-distort the image in order to counteract the pincusion effect produced by the rift's lenses. The distortion algorithm was specified in the documentation as a barrel distortion, with specific radial scaling parameters, and an accompanying sample HLSL shader program to implement it, but was otherwise left to the application.
The new SDK, while still being able to work in a similar way (which is now dubbed: "client distortion rendering" in the documentation), also provides a higher level interface (SDK-based distortion) which given the rendered texture(s), takes care of presenting it properly distorted and corrected onto the rift's display. The benefits of this new approach are obviously that future releases may improve the distortion and chromatic abberation correction algorithms without extra effort on the app-side, but also since the SDK now knows the time interval between requesting head-tracking information and final drawing to the HMD, it can do funky hacks to reduce apparent lattency, and make the VR experience much smoother.
Here's an overview of the tasks required by the application, to utilize the oculus rift through the Oculus SDK (0.4.2):
ovr_Initialize and
WindowPos in
ovrHmd structure), and make it fullscreen there.
ovrGLTexture structure by filling it with information about the framebuffer texture(s) we created and the area in them which will contain each image. This will be passed to the
ovrHmd_EndFrame function during our drawing loop to let the SDK distort and present our renderings to the user.
ovrGLConfig structure and passing it to
ovrHmd_BeginFrame and bind the render target fbo.
ovrMatrix4f_Projection and use it.
ovrHmd_GetEyePose. It returns a structure containing a translation vector and a rotation quaternion, which we'll have to set/multiply with our view matrix.
ovrHmd_EndFrame giving it a pointer to the
ovrGLTexture structures we filled in earlier describing our rendertarget texture(s).
I wrote a very simple test program (see screenshot at the top of this article), demonstrating all of the above and released it as public domain. You may grab the code from my mercurial repository: http://nuclear.mutantstargoat.com/hg/oculus2. To compile it you'll need the Oculus SDK library, SDL2, and GLEW. The repo includes VS2013 project files to build on windows. As soon as the GNU/Linux version of the Oculus SDK is released, I'll port it and push an updated version.
In closing, I just have to mention a new project I started last week called libgoatvr. It's a VR abstraction library, which presents a simple unified API for VR programs, while supporting multiple runtime-switchable backends such as the oculus SDK and OpenHMD. I intend to base all my future VR projects on this library, so that I can switch back and forth between the various VR backends effortlessly, to try new features, avoid vendor lock-in, and stop relying solely on the whims of a proprietary SDK developer.
The original release of this wedtro was during the summer of 2003, in the hayday of the "second coming of the Greek demoscene". Our friend Cybernoid was getting married, and we (Nuclear / The Lab and Imak / Quadra) decided to make him a wedtro as a wedding present.
Imak came to my place, with his perlin noise procedural texture generation code, while pulled in my Direct3D 8.0 3D engine, that I had used for Absence a few months earlier. I also made a couple of crappy objects in 3d studio max, and we dug up an old fasttracker module by Thor/Quadra, which seemed cute and cuddly enough for the occasion.
My 3D engine code had rotted away apparently. Probably I was making half-assed changes and attempts to add new features after the release of Absence, and the wedtro effort was plagued with bugs from the start. I seem to remember that even trying to do a fade-out at some point with a blended fullscreen quad took us a long time to make it work. On top of everything else, Raoul/nlogn also dropped by, insisting to show us games on his dreamcast for some reason (Ikaruga and Rez if I remember correctly).
We didn't manage to finish the prod before the "deadline" (wedding day), but we managed to send it to them, the day after: http://www.pouet.net/prod.php?which=10431.
A few years later, no computer in the known universe managed to run this wedtro correctly. I first noticed the bug on an ATI card, and my first reflex was to blame their crappy drivers as usual, but it turned out that no modern graphics card was able to render it correctly.
I finally decided to look into it around 2011, and see if I can find out why it broke over the years. I had since lost the source code of the demo itself, in the NFS-symlink
rm -rf fiasco of 2008, so a fix was out of the question. But I had the code of the 3D engine (or at least a version of it) still, so I could at least satisfy my curiosity.
It turns out, I had two code-paths in the high-level
Object::Render code:
if(TexUnits < 4) { Render2TexUnits(); } else { Render4TexUnits(); }
These calls managed the hellish fixed-function multitexturing API, to render the
Objects with all their materials and textures.
Render2TexUnits would be called on graphics cards with less than 4 texture units, and would use more render passes to blend all the textures correctly, while
Render4TexUnits was able to render everything in just one or two passes, on capable hardware.
Problem is, when I was writing that code, I only had a Geforce2 MX, which as was typical of that era, only had 2 texture units. So, the 4-texture-unit code path was never actually tested. And it turns out, there was a lurking copy-paste bug in there, to ruin my decade.
There was a check in the begining of both these functions: if the caller requested to draw withot writing to the zbuffer, they masked zbuffer writes for the duration of the call. But while Render2TexUnits did:
void Object::Render2TexUnits() { if(!rendp.ZWrite) gc->SetZWrite(false); ... do all the setup and drawing ... if(!rendp.ZWrite) gc->SetZWrite(true); }
In Render4TexUnits, the following copy-paste bug went unnoticed:
void Object::Render4TexUnits() { if(!rendp.ZWrite) gc->SetZWrite(false); ... do all the setup and drawing ... if(!rendp.ZWrite) gc->SetZWrite(false); }
As soon as one object was rendered with zwrites masked, nothing from that point on could ever write to the zbuffer again. So when the blended firework particles started being rendered, with zwrites disabled, in the wedtro, the cake and everything else from that point on became messed up…
Fast-forward a few years (2014), and the wedtro bug still bugs me. It's bugging me for a decade now… so I decided to try and do something about it. Fuck the source code; I download a disassembler (IDA Pro freeware), make a copy of wedtro.exe and start digging.
My initial plan was to locate
Object::Render and make the call to
Render2TexUnits unconditional. But it's kinda tricky going through vtables to find which virtual function is which (of course I had no debug symbols in the binary, which was compiled with msvc in release mode). So I started looking for the initialization code, which was simpler to locate since it referred to a lot of error strings like "Could not create Direct3D device", etc.
As luck would have it, immediately after two successive instances of
throw EngineInitException("Could not create Direct3D device"), there was a block of code pulling the relevant bits from the D3DCAPS8 structure and putting them in class variables:
gc->WindowHandle = WindowHandle; gc->D3DDevice->GetRenderTarget(&gc->MainRenderTarget.ColorSurface); gc->D3DDevice->GetDepthStencilSurface(&gc->MainRenderTarget.DepthStencilSurface); gc->ContextParams = *GCParams; gc->ZFormat = zfmt; gc->AASamples = AASamples; gc->ColorFormat = FinalColorFormat; gc->MaxTextureStages = adapters[AdapterID].Capabilities.MaxSimultaneousTextures;
gc->MaxTextureStages is exactly what we needed to stay less than 4, to avoid taking the branch into
Object::Render4TexUnits during drawing.
I followed the
call instructions in the debugger, matching the number of arguments with the push instructions preceding them (2 pushes for 1 argument in the code, because of the hidden this pointer argument). Then I went over a
rep movsd which was obviously the
gc->ContextParams = *GCParams line.
I proceeded to set a breakpoint on the next instruction after that:
mov ecx, [esp+1b0h+var_194] mov [ebp+42d0h], ecx
and ran the program to see if it is plausible that it's the
gc->ZFormat = zfmt line of the C++ source. I saw that it moved the value 75, which according to the D3D docs, corresponds to the
D3DFMT_D24S8 enumeration, a zbuffer format!
The layout of the member variables of any class instance in memory, follow exactly the order in which they where declared in the source. GraphicsContext, according to the "3dengine.h" header file has:
D3DFORMAT ColorFormat, ZFormat; int AASamples; int MaxTextureStages;
So, since ZFormat was stored at
[ebp+42d0h], it follows that
MaxTextureStages should be at offset 42d8h. Indeed a few lines later, we encounter the instructions:
mov eax, [edx+ecx+0d0h] mov [ebp+42d8h], eax
Step a couple of times to reach these lines, and see what gets loaded into eax, expecting to see the value 8 for any modern graphics card, and bingo: the magic value 8 appears in eax! Manually zero-out the contents of eax and let the program continue, while praying to Odin… and victory! The beauty of a perfectly z-ordered wedding cake almost blinds me.
From that point on, everything is straightforward. Going to hex-view shows that the instruction
mov eax, [edx+ecx+0d0h] corresponds to the 7 opcode bytes:
8B 84 0A D0 00 00 00. Not wanting to be buggered by complex move instructions with mod-r/m plus displacement bytes in the opcode, I decided to just replace it with
xor eax,eax (setting eax to 0), which is a very simple 2-byte opcode. Going through the intel manuals, I found that
xor eax,eax is encoded as:
31 C0, leaving 5 more bytes of the original instruction to be filled with NOPs (opcode 90). So I made the change with a hex editor, and the result is a fixed wedtroid executable, which everyone can enjoy :)
Feel free to download the fixed repack of wedtroid if you want to watch it (windows only unfortunately, though wine should have no difficulty running it too).
Now, I'm always pissed off from the start when I have to write code on windows and visual studio, but having to deal with 3dsmax on top of that, really just adds insult to injury. It's not just that maxsdk is a convoluted mess. Or that it needs a very specific version of visual studio to write plugins for it (which is really Microsoft's fault, to be fair). No, my biggest issue so far is that 3dsmax takes about 3 years to start up, and there is no way to unload, or reload a plugin without restarting it.
Whenever I fix a tiny thing in the exporter plugin I'm writting, and I want to try it out and see if it does the buissiness, I have to shut down 3dsmax, start it up again (which takes forever), load my test scene, then try to export again and see what happens. This is obviously unacceptable, so I really had to do something about it.
But first let's examine how exporter plugins are handled by 3dsmax. The 3dsmax installation directory contains a subdirectory called plugins. At startup, it looks into that directory, and loads all the plugins located there. Plugins are obviously just DLLs, but with a particular naming convention for their suffix, so that 3dsmax will know how to treat them as different plugin classes. For instance, exporter plugins must be named with a .dle suffix.
Exporter plugins are supposed to define a subclass of SceneExport, which overrides the DoExport function. When 3dsmax loads the plugin dll, it pulls from it a function called LibCreate, which is supposed to create and return an instance of this class. Then, whenever the user tries to export a scene of the type registered by this plugin, the appropriate DoExport function is called, to do it.
So as I mentioned previously, the problem is that plugin DLLs can't be unloaded and reloaded while 3dsmax is running, making it necessary to shut down 3dsmax and restart it all the time, while writing my exporter.
After cursing Autodesk and their stupid plugin system for a while, I came up with a pretty neat idea to circuimvent that restriction. Instead of letting 3dsmax grab hold of my exporter DLL when it starts, what if I write a second exporter DLL that is just a stub, a proxy if you will. What if that stub gets loaded by 3dsmax at startup, but my actual exporter plugin DLL is separate, 3dsmax doesn't even know about it, and the stub exporter loads it up on demand, and passes through the DoExport call!
With this scheme, it doesn't actually matter much that plugins can't be unloaded by 3dsmax, because my plugin wasn't loaded by 3dsmax in the first place. I'm loading it on demand when the user requests an export, and releasing it immediately after the export is done.
Turns out, this works beautifully. I created post-build events for both projects (maxgoat, and maxgoat_stub) that copies the DLLs in the 3dsmax plugin directory, but only the maxgoat_stub post-build event changes the suffix to ".dle". The actual exporter is left with the original ".dll" suffix, and 3dsmax ignores its existence.
The only tricky bit the stub DLL has to do in order to load and use the real exporter DLL, is to find the plugin directory where both of them are installed. This little snippet of win32 barf handles that correctly:
static const char *find_dll_dir() { static char path[MAX_PATH]; HMODULE dll; if(!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)find_dll_dir, &dll)) { return 0; } GetModuleFileNameA(dll, path, sizeof path); char *last_slash = strrchr(path, '\\'); if(last_slash) { *last_slash = 0; } return path; }
At that point it can happily proceed to load the actual exporter DLL, and call everything it needs to, in order to perform the export. Here's the whole DoExport function of the stub, with all error handling removed for brevity:
int GoatExporterStub::DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL non_interactive, DWORD opt) { static const char *dll_fname = "maxgoat.dll"; const char *plugdir = find_dll_dir(); char *dll_path = new char[strlen(dll_fname) + strlen(plugdir) + 2]; sprintf(dll_path, "%s\\%s", plugdir, dll_fname); // load plugin and grab all the functions we need HMODULE dll = LoadLibraryA(dll_path); ClassDescFunc get_class_desc = (ClassDescFunc)GetProcAddress(dll, "LibClassDesc"); InitFunc init = (InitFunc)GetProcAddress(dll, "LibInitialize"); ShutdownFunc shutdown = (ShutdownFunc)GetProcAddress(dll, "LibShutdown"); init(); ClassDesc *desc = get_class_desc(0); // create the exporter instance and call DoExport SceneExport *ex = (SceneExport*)desc->Create(); int res = ex->DoExport(name, eiface, iface); delete ex; shutdown(); delete [] dll_path; FreeLibrary(dll); return res; }
With this system in place, iterating on figuring out all the maxsdk bullshit is a breeze. Just keep 3dsmax open with my stub plugin loaded all the time, compile/install the exporter at will, and hit export again from within 3dsmax. The current version of the exporter DLL is automatically loaded, used and shoved out of the way again. The whole process becomes almost enjoyable.
For a long time, I was a big fan of backwards (bottom-up) lazy evaluation of transformation hierarchies. Essentially having an
XFormNode class for each node in the hierarchy with a
get_matrix(long msec) function which calculates the current node's transformation matrix for the current time, then calls
parent->get_matrix(msec) and returns the concatenated matrix.
Matrix4x4 XFormNode::get_matrix(long msec) const { Matrix4x4 xform; calc_matrix(&xform, msec); if(parent) { xform = parent->get_xform(msec) * xform; } return xform; }
Of course, such a scheme would be wasteful if these matrices where calculated every time
get_matrix functions are called. For instance if a node is part of a hierarchy, then its
get_matrix will be called when we need to draw the object corresponding to this node, and also every time the
get_matrix of any one of its descendants is called, due to the recursive bottom-up evaluation of matrices outlined previously. If one considers the posibility of drawing an object multiple times for various multi-pass algorithms the problem gets worse, with the limiting worse case scenario being if we're doing ray-tracing which would require these functions to be called at the very least once per ray cast.
It follows then, that such a design goes hand in hand with lazy evaulation and caching of calculated node matrices. The XFormNode class would hold the last requested time and corresponding matrix, and when
get_matrix is called, if the requested time matches the last one, we just return the cached matrix instead of recalculating it.
const Matrix4x4 &XFormNode::get_matrix(long msec) const { if(msec == cached_msec) { return cached_matrix; } calc_matrix(&cached_matrix, msec); cached_msec = msec; if(parent) { cached_matrix = parent->get_xform(msec) * cached_matrix; } return cached_matrix; }
This worked nicely for a long time, and it worked like magic. At any point I could just ask for the transform at time X and would get the matrix automatically, including any effects of hierarchy, keyframe interpolations, etc. It's all good… until suddenly processors stopped getting faster any more, moore's law went belly up, and after the shock passed we all sooner or later realised that single-threaded graphics programs are a thing of the past.
In the brave new multithreaded world, lazy evaluation becomes a pain in the ass. The first knee-jerk reaction is to add a mutex in XFormNode, and lock the hell out of the cached matrices. And while that might be ok for an OpenGL program which won't have more than a couple of threads working with the scene database at any point (since rendering itself can only be done safely from a single thread), it throws out of the window a lot of concurrency that can take place in a raytracer where at any point there could be 8 or more threads asking for the matrix of any arbitrary node.
A second way to deal with this issue is to have each thread keep its own copy of the matrix cache, keeping it in thread-specific memory. I'm shamed to admit I never got around to doing any actual performance comparisons on this, though I've used it for quite some time in my programs. In theory it avoids having to wait for any other thread to access the cache, so it should be faster in theory, but it needs a
pthread_getspecific call in every
get_matrix invocation which comes with its own overhead.
const Matrix4x4 &XFormNode::get_matrix(long msec) const { MatrixCache *cache = pthread_getspecific(cache_key); // cache_key created in the constructor for each node if(!cache) { // first time we need a cache for this thread we'll have to create it cache = new MatrixCache; pthread_mutex_lock(&cache_list_lock); cache_list.push_back(cache); pthread_mutex_unlock(&cache_list_lock); pthread_setspecific(cache_key, cache); } if(msec == cache->msec) { return cache->matrix; } calc_matrix(&cache->matrix, msec); cache->msec = msec; if(parent) { cache->matrix = parent->get_xform(msec) * cache->matrix; } return cache->matrix; }
This works fine, and although we managed to avoid blocking concurrent use of
get_matrix, we had to add some amount of overhead for thread-specific storage calls, and the code became much more complex all over the place: invalidations must also access this thread-specific storage, we need cleanup for the per-thread MatrixCache objects, etc.
So nowadays I'm starting to lean more towards the simpler, less automagic design of top-down evaluation. It boils down to just going through the hierarchy once to calculate all the matrices recursively, then at any point we can just grab the previously calculated matrix of any node and use it.
void XFormNode::eval(long msec) { calc_matrix(&matrix, msec); if(parent) { matrix = parent->matrix * matrix; } for(size_t i=0; i<children.size(); i++) { children[i]->eval(msec); } }
The simplicity of this two-pass approach is hard to overlook, however it's just not as good for some things as my original ideal method. It works fine for OpenGL programs where it suffices to calculate transformations once per frame, it even works fine for simple raytracers where we have again a single time value for any given frame. However it breaks down for ray-tracers doing distribution ray tracing for motion blur.
The best way to add motion blur to a ray tracer is through a monte-carlo method invented by Cook, Porter and Carpenter, called "distribution ray tracing". In short, when spawining primary rays we have to choose a random time in the interval centered around the frame time and extending to the past and future, as far as dictated by the shutter speed of the camera. This time is then used both to calculate the position and direction of the ray, which thus might differ between sub-pixels if the camera is moving, and to calculate the positions of the objects we're testing for intersections against. Then if we cast many rays per pixel and average the results, we'll get motion blur on anything that moves significantly while the virtual shutter is open (example from my old s-ray renderer).
It's obvious that calculating matrices once per frame won't cut it with advanced ray-tracers, so there's no getting rid of the complexity of the lazy bottom-up scheme in that case. Admittedly, however, caching won't do much for us either because every sub-pixel will request the matrix at a different time anyway, so we might as well just calculate matrices from scratch all the time, and skip the thread-specific access overhead. The jury is still out on that one.
Do you have a favourite design for hierarchical animation code? Feel free to share it by leaving a comment below!
It's obvious that to be able to generate multiple primary rays for each pixel, we need to have an algorithm that given the sample number, calculates a sample position within the area of the a pixel. Since it's trivial to map points in the unit square, onto the actual area of an arbitrary pixel, it makes sense to write this sample position generation function, so that it calculates points in the unit square.
The easiest way to write such a function would be to generate random points in the unit square, like this:
void get_sample_pos(float *pos) { pos[0] = (float)rand() / (float)RAND_MAX - 0.5; pos[1] = (float)rand() / (float)RAND_MAX - 0.5; }
The problem with this approach is that, even if our random number generator really has a perfectly uniform distribution, any finite number of sample positions generated, especially if that number is in the low tens, will probably not cover the area of the pixel in anything resembling a uniform sampling. Clusters are very likely to occur, leaving large areas of the pixel space unexplored by our rays.
As the number of samples gets larger and larger, this problem is somewhat mitigated, but especially if we're not writting a path tracer, we're usually dealing with anything between 4 to 20 rays per pixel, no more.
The following animation shows random sample positions generated by the code above. Even at about 40 samples, the left part of the pixel is inadequately sampled.
Another approach is to avoid randomness. The following function gets the sample number as input, and calculates its position by recursively subdividing the pixel area, taking care to spread the samples of each recursion level around as much as possible instead of focusing on one quadrant at a time.
void get_sample_pos(int sidx, float *pos) { pos[0] = pos[1] = 0.0f; get_sample_pos_rec(sidx, 1.0f, 1.0f, pos); } static void get_sample_pos_rec(int sidx, float xsz, float ysz, float *pos) { int quadrant; static const float subpt[4][2] = { {-0.25, -0.25}, {0.25, -0.25}, {-0.25, 0.25}, {0.25, 0.25} }; /* base case: sample 0 is always in the middle, do nothing */ if(!sidx) return; /* determine which quadrant to recurse into */ quadrant = ((sidx - 1) % 4); pos[0] += subpt[quadrant][0] * xsz; pos[1] += subpt[quadrant][1] * ysz; get_sample_pos_rec((sidx - 1) / 4, xsz / 2, ysz / 2, pos); }
And here's the animation showing that code in action (colors denote the recursion depth):
This sampling is perfectly uniform, but it's still not ideal. The problem is that whenever we're sampling in a regular grid, no matter how fine that grid is, we will introduce aliasing. By breaking up each pixel into multiple subpixels like this we effectively increase the cutoff frequency after which aliasing occurs, but we do not eliminate it.
The best solution is to combine both techniques. We need randomness to convert aliasing into noise, which is much less perceptible by human brains trained by evolution to recognize patterns. But we also need uniform sampling to properly explore the whole area of each pixel.
So, we'll employ a technique known as jittering: first we uniformly subdivide the pixel into subpixels, and then we randomly perturb the sample position of each subpixel inside the area of that subpixel. The following code implements this algorithm:
void get_sample_pos(int sidx, float *pos) { pos[0] = pos[1] = 0.0f; get_sample_pos_rec(sidx, 1.0f, 1.0f, pos); } static void get_sample_pos_rec(int sidx, float xsz, float ysz, float *pos) { int quadrant; static const float subpt[4][2] = { {-0.25, -0.25}, {0.25, -0.25}, {-0.25, 0.25}, {0.25, 0.25} }; if(!sidx) { /* we're done, just add appropriate jitter */ pos[0] += (float)rand() / (float)RAND_MAX * xsz - xsz / 2.0; pos[1] += (float)rand() / (float)RAND_MAX * ysz - ysz / 2.0; return; } /* determine which quadrant to recurse into */ quadrant = ((sidx - 1) % 4); pos[0] += subpt[quadrant][0] * xsz; pos[1] += subpt[quadrant][1] * ysz; get_sample_pos_rec((sidx - 1) / 4, xsz / 2, ysz / 2, pos); }
And here's the animation showing the jittered sample position generator in action:
The gist of the problem with traditional real-time rendering, is that we're trying to do linear operations, in non-linear color spaces.
Let's take lighting calculations for example, when light hits a plane with 60 degrees incidence angle from the normal vector of the plane, Lambert's cosine law states that the intensity of the diffusely reflected light off the plane (radiant exitance), is exactly half of the intensity of the incident light (irradiance) from that light source. However the monitor, responsible for taking all those pixel values and sending them rushing into our retinas, does not play along with our assumptions. That half intensity grey light we expect from that surface, becomes much darker due to the exponential response curve of the electron gun.
Simply put, when half the voltage of the full input range is applied to the electron gun, much less than half the possible electrons hit the phosphor in the glass, making it emmit lower than half-intensity light to the user. That's not a defect of the CRT monitors; all kinds of monitors, tv screens, projectors, or other display devices work the same way.
So how do we correct that? We need to use the inverse of the monitor response curve, to correct our output colors, before they are fed to the monitor, so that we can be sure that our linear color space where we do our calculations, does not get bent out of shape before it reaches our eyes. Since the monitor response curve is approximately a function of the form: where usually, it mostly suffices to do the following calculation before we write the color value to the framebuffer: . Or in a pixel shader:
gl_FragColor.rgb = pow(color.rgb, vec3(1.0 / 2.2));
That's not entirely correct, because if we are doing any blending, it happens after the pixel shader writes the color value, which means it would operate after this gamma correction, in a non-linear color space. It would be fine if this shader is a final post-processing shader which writes the whole framebuffer without any blending operations, but there is a better and more efficient way. If we just tell OpenGL that we want to output a gamma-corrected framebuffer, or more precisely a framebuffer in the sRGB color space, it can do this calculation using hardware lookup tables, after any blending takes place, which is efficient and correct. This fucntionality is exposed by the ARB_framebuffer_sRGB extension, and should be available on all modern graphics cards. To use it we need to request an sRGB-capable framebuffer during context creation (GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB / WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB), and enable it with
Now if we do just that, we're probably going to see the following ghastly result:
The problem is that our textures are already gamma-corrected with a similar process, which makes them now completely washed out when we apply gamma correction in the end a second time. The solution is to make color values looked up from textures linear before using them, by raising them to the power of 2.2. This can either be done in the shader simply by: pow(texture2D(tex, tcoord).rgb, vec3(2.2)), or by using the GL_SRGB_EXT internal texture format instead of GL_RGB (EXT_texture_sRGB extension), to let OpenGL know that our textures aren't linear and need conversion on lookups.
The result is correct rendering output, with all operations in a linear color space:
A final pitfall we may encounter is if we use intermediate render targets during rendering, with 8 bit per color channel resolution, we will observe noticable banding in the darker areas. That is because our 8bit/channel textures are now raised to a power and the result is again placed in an 8bit/channel render target, which obviously wastes color resolution and loses details, which cannot be replaced later on when we gamma correct the values again. Bottom-line is that we need higher precision intermedate render targets if we are going to work in a trully linear color space. The following screenshots show a dark area of the game when using a regular GL_RGBA intermediate render target (top), and when using a half-float GL_RGBA16F render target (bottom):
Color artifacts are clearly visible in the first image, around the dark unlit area.


text:
WR FA 5 years ago
Miles Austin caught four passes for 45 yards and a touchdown in Sunday's Week 16 overtime loss to the Saints.
Austin was targeted eight times on the day, but he battled a case of the drops in the second half and was booed by the Dallas faithful. His fourth-quarter, 19-yard touchdown came on fourth-and-ten with 0:15 left in regulation and ended up sending the game to overtime. Austin needs 67 yards in Week 17 against the Redskins to post his third 1,000-yard season. He was held without a catch in Week 12 versus Washington.

subset: commoncrawl


text:
The 2 DS and I will be Stateside this summer. If any members fancy dinner/lunch/coffee please just let me know...Closest thing We can get to a G2G... LOL....Unless SI charters a plane to Germany...
We are in DC... 14-17 August and 25 August
Charlottesville, VA ..18 August
Hartford, Conneticut 26-29 August
We must let go of the life we have planned, so as to accept the one that is waiting for us.
[This message edited by cryingdaily at 3:38 PM, July 18th (Thursday)]
2 hours in Europe can have you 2 countries away!!!!!! Hard to imagine that is "nearby"' for our American friends
just PM me if you are going to be nearby.... could be fun
Not totally sure about the dates... Will be finishing up school that week. I normally drag everyone to happy hour, but you have teenagers....


text:
RatingRate me!
Found in:
2 cups almonds, soaked 24 hours and drained.
2 cups fresh raspberries
1/4 cup dried papaya, soaked 1 hour, and drained
1 cup cucumber juice or coconut water
Recipe Directions
place all the ingredients in a blender and process to a porridge consistency. and juice in slowly to keep the porridge from becoming too runny.
Print This Recipe (PDF)
Click the button below to download the printable PDF.
Top voted
Leave a Comment
The Rawtarian wants to hear from you! Let's get the conversation going! Leave a comment or review below.
Hello Beautiful!
It looks like you're new to The Rawtarian Community. If you'd like to get involved, click one of these buttons!Login to Community Signup for an account Login using Facebook


text:
The emergency room admissions clerk is the frontline of an outdated legal understanding of family.
What 'Next of Kin' Means
Melynda Price is an associate professor at the University of Kentucky College of Law and blogs at Thoughts of an Ivory Tower Interloper.
Updated June 27, 2012, 6:50 PM
I am a single parent. Yet our family is more than mother and child. When my son was 6 months old, I touched him and his little body was on fire. A new mom plus a 104-degree fever equals a trip to the emergency room. After asking about symptoms and insurance, the next question was: Who is your next of kin? This trip to the E.R. began two years (and counting) of asking questions, acquiring documents and strategizing the what-ifs. Who would speak for him if I were incapacitated or just unavailable?
We live nearly a thousand miles from our closest blood relative, but if you ask my son, he can lead you to his Aunt Kaki across the street and Godmama around the corner. In his toddler vocabulary of family, they are as close to him as Grandma in Texas and my sister in New Jersey. The law gives all kinds of bureaucrats and paper pushers the power to tell people like me that my definition of family is invalid and therefore can be disregarded. It ignores the relationships we choose in favor of ones that are easy and comfortable.
I answered the next of kin question quickly. My friend, birth coach and now godmother to my 2 year-old boy was the obvious choice. When I was pregnant and alone, she cared for us. Still, the harder question is, will anyone listen to my chosen kin? The emergency room admissions clerk is the front line of an outdated legal understanding of family. Single mothers, same-sex couples and other familial forms that do not meet the heterosexual ideal have to fight for recognition. Because I am a lawyer and I have resources, I can codify the desires of my heart in medical guardianships and other legal forms. Not everyone can. Even armed with documents, however, I am not sure if my designee would be allowed to do what I have asked, particularly in a conservative state or anywhere a small-minded person guards the door between my child and whom he knows to be family.
Each fall, I teach my students about the legal theory of consent. I emphasize that the law gives individuals autonomy to determine what happens in their lives. Right now the law uses biological definitions of family as shorthand for consent, but biology is only a proxy for trust. Family is knowing who you can rely on when the spirit is low and the stakes are high. The law has been slow to incorporate this truth. But families like mine keep fighting for its recognition and our inclusion in how the law defines kinship.
Join Opinion on Facebook and follow updates on twitter.com/roomfordebate.


text:
The summer and fall months are loaded with century, metric century, three-day and week-long bicycle tours. The excitement of riding an event with several other cyclists can be invigorating and motivating.
You can use an organized tour as a season goal or a means of bumping up your fitness for other events. For example, week-long tours can be used as "crash training" weeks. Crash training is an overload of training volume and/or intensity. A well-structured crash week followed by adequate rest can have significant, positive effects on fitness.
More: How to Prepare for an Ultra-Distance Event
Well-planned crash training works wonders, but the last thing you want to do is crash during a tour. The excitement and fatigue of an organized ride might cause some people to lose their wits.
Before your turn the pedals on a tour, consider these few common sense tips to stay safe and courteous.
More: 12 Training Tips for an Ultra-Distance Ride
? If you are not accustomed to riding in a pace line (several cyclists following closely behind one another) don't attempt it during your first organized tour. If you want to learn the skill, seek the help of a local bicycling club or practice with a small group of friends. See also my column covering basic skills for group riding.
? Some riders consider it rude if you "sit" on their wheel and draft. If you don't know the person and haven't asked permission to be sitting on their wheel, not only can it be rude, it can be dangerous or disgusting.
If the lead rider doesn't know you're there, they won't point out road hazards. When they move quickly to avoid a pot hole or road hazard, you may end up hitting it. Along the disgusting line, if your lead rider doesn't know you're drafting, they may decide to clear their throat or nose into the wind, depositing the goo on you.
More: How to Train for a Week-Long Bike Tour
? Keep your head up and look ahead several feet. This is a problem with experienced and inexperienced riders alike. Often, riders look down at the road, eyes focused on a spot about 10 feet ahead of their bicycle. Focusing on a spot this close causes trouble.
Experts1 estimate average human reaction time to be somewhere between 1 and 1.5 seconds. If you are riding 15 miles per hour, you are traveling 22 feet per second. By the time you see something 10 feet in front of you and react, it's too late, you've hit the hazard. Obviously, the problem compounds itself the faster you're traveling. (20 mph = 29 ft/sec, 25 mph = 37 ft/sec)
- 1
- of
- 2


text:
New Dragon Ball Z Anime Announced – "About Time!"
- Categories: Anime, News
- Date: Apr 29, 2015 17:16 JST
- Tags: Announcements, Continuations, Dragon Ball Z, Retro, Toei
World-renowned fighting series Dragon Ball Z is receiving a brand new TV anime in the form of "Dragon Ball Super", with long-time fans of the highly popular series being taken aback by its rather abrupt emergence, even if still probably overjoyed nonetheless.
Dragon Ball Super will be the first entry into the venerable series in over 18 years, and will feature an original story written by none other than the creator of the Dragon Ball manga himself, Akira Toriyama.
The new iteration is part of the remastered Dragon Ball Kai series that is currently airing on TV and is planned to take place after the events of the Majin Buu arc, which fans will likely esteem due to th apparente decision to disregard Dragon Ball GT's existence in its entirety.
Dragon Ball Super will make its arrival in July.


text:
Rooftop unit
Advantix Systems' DuTreat Roof HVAC system is a single-pieice unit that utilizes liquid desiccant technology.
Advantix Systems' DuTreat Roof HVAC system utilizes liquid desiccant technology. The system is a single-piece unit that operates using electricity alone and requires minimal installation. It also cleans air and eliminates odors without disposable filters in each pass (80% removal of particulates/91% of airborne microorganisms). It controls temperature and humidity independently for any sensible heat ratio largest packaged unit of liquid desiccant technology. It is field convertible for vertical/horizontal airflow configurations. Other features include corrosion-resistant wetted components, a variable capacity digital scroll compressor, and direct drive, belt-free fans.
Advantix Systems
Post a comment
Log in or create an account to submit your comment for this article.
Log in or create an account to submit your comment for this article.


text:
RHS STUDENT OF THE WEEKThis week's RHS Student of the week is freshman Caroline Wilde. The daughter of Doug and LeAnn Wilde, she was nominated by RHS teacher Cindy Saegert, who believes that she is one of the most responsible students on campus. Wilde is an active member of RHS student council and also enjoys home design.
The student of the week program, sponsored by P.A.L., encourages students to exhibit positive character traits. Teachers were asked this week to nominate students who are responsible and all nominees were placed in a drawing. Winners receive a sign in their yard announcing the honor and are featured on a bulletin board on campus.


text: I finished my GGS's crib quilt today. While working on it my DH told me to go ahead & order the walking foot & the FMQ foot for my machine. They came in just in time & I did all the quilting after the sandwiching with them. Both were much easier than I expected. Today I learned to meander. After being terrified of it for over a week, it really didn't come out too bad, but I need a lot more practice because the smaller areas have smaller meanderings & larger areas have larger ones. I put a picture up in the picture section. To the "newbies" of which I am one...don't be scared of it; it's not so bad!!


text:
With the cosmopolitan cafes of Amman, the peace of hilltop Dana and the historic treasures of Madaba, you may come to Jordan to see the ruins of Petra, but you'll leave having encountered so much more.
Cyber Sale on now! 15% OFF all trips* departing February 1 - September 30, 2018. Book by November 30th.Terms & Conditions
|Trip name
|From USD
17 Feb 2018Explore Jordan
|View Trip
15 Mar 2018Jordan Discovery
|View Trip
29 Mar 2018Jordan Real Food Adventure
|View Trip
31 Mar 2018Trek Jordan
|View Trip
1 Apr 2018Jordan Family Holiday
|View Trip
14 Apr 2018Cycle Jordan (Petra & Wadi Rum)
|View Trip
5 May 2018Explore Jordan, Israel & the Palestinian Territories
|View Trip
Travel to Jordan and tour Amman, Madaba and the inspiring landscape of Wadi Rum. Take a...
Travel from the Jordanian capital, Amman, to the seaside town of Aqaba, through the...
Travel to Jordan and tour Amman, Madaba and the inspiring landscape of Wadi Rum. Trek...
Take an adventure holiday through Egypt and Jordan. Visit Cairo, the Pyramids of Giza,...
Explore the best of the Middle East as you discover Jordan and Israel. Explore Wadi Rum...
Get a taste of Jordan via Amman, Petra and Wadi Rum. See why this jewel of the Levant...
Travel to Egypt and experience the history and culture of the land of the pharaohs on a...
Follow in the footsteps of prophets on an adventure tour through Jordan and Egypt....
Embark on an unforgettable small group adventure through the majestic lands of Jordan...
Pedalling past Petra, Jerash, Mount Nebo, Wadi Rum and more – experience the best...
Experience the best of the Middle East across Jordan, Egypt, Israel & Palestine....
Travel to Jordan and tour Amman, Madaba and the inspiring landscape of Wadi Rum. Take a...
Discover the delectable dishes of Israel and the Palestinian Territories. Savour...
Travel to Jordan and visit Petra, the ancient 'lost city'. Be awed by ancient...
Discover lost cities on a family adventure in Jordan. From the capital Amman to the...
Travel from Egypt to Turkey on this magical Middle East Discovery tour. See the...
Adventure from portside Muscat and Muttrah into the heart of Oman's richly coloured...
Our Jordan trips score an average of 4.83 out of 5 based on 236 reviews in the last year.
Make sure you read the physical requirements for your trip to make sure it is appropriate for your fitness level. Read Essential Trip Notes carefully to know exactly what is included. Work out currency amounts and adaptors before you go. Go with an open mind, particularly to less developed countries.
Review submitted 24 Nov 2017
Wadi rum and Petra are must see destinations.
Review submitted 22 Nov 2017
By going with a group, I knew my transportation would be insured, my activities...
Petra, Wadi Rum, the Dead Sea...Jordan's biggest attractions are well worth a...
In 1992, I travelled to Egypt, Israel and Jordan with about as much forethought as...
Upon arriving in Jordan, the first thing you'll hear is, "Where are you from?" And...
Goodlooking, humble and hot - Jordan's got all the right qualities for a perfect...
At a time when much of the region sadly seems to be wracked by upheaval and unrest...
People packing for a Jordan adventure have to be prepared for all conditions....
See the well-preserved Roman ruins of Jerash
Relax in the resort town of Aqaba
Camp under the stars with Bedouin in Wadi Rum
Intrepid believes half the fun of experiencing a new country is getting there, and getting around once there! Where possible, Intrepid uses local transport options and traditional modes of transport - which usually carry less of an environmental impact, support small local operators and are heaps more fun.
Depending on which trip you're on while in Jordan, you may find yourself travelling by:
Head out for a day of dune-bashing in a 4x4. Scale the towering desert dunes and take in the sweeping views. A fun way to explore remote parts of Jordan.
Travelling with Intrepid is a little bit different. We endeavour to provide travellers with an authentic experience to remember, so we try to keep accommodation as unique and traditional as possible.
When travelling with us in Jordan you may find yourself staying in a:
Be welcomed by Bedouin for a night of camping under the stars. Enjoy traditional food and music then fall asleep in the supreme silence of the desert.
Visas are required by all visitors entering Jordan. Single entry visas valid for 14 days and can be obtained by most nationalities on arrival at the airport in Amman or at the Jordanian border for approximately JOD40. It can be significantly more expensive to acquire your visa from the embassy in your home country. If you require a stay longer than 14 days, visas obtained from the embassy in your home country will be valid for two months.
Tipping is up to the individual in Jordan. Hotels and up-market restaurants typically add a surcharge that is included in bills, which is usually 10%. Rounding up bills and leaving spare change is a good idea when dining in smaller restaurants and when using taxis.
Internet access is growing rapidly in Jordan. Internet can usually be accessed from hotels and internet cafes in major cities. Expect little to no access in small towns, villages and other rural areas.
Mobile phone coverage is good in Jordan's major cities and built-up areas like Amman and Aqaba. Expect limited to no phone coverage in more isolated areas like the desert. Ensure you have global roaming activated on your phone before leaving home.
Western-style toilets are common in modern hotels, malls and at popular tourist areas. Squat toilets are the standard throughout the rest of the country. Sometimes, you may need to pay and bring your own toilet paper when visiting public rest rooms.
Street snack = 3 JOD
Can of soft drink = 1 JOD
Dinner at a restaurant = 10 JOD
Embroidered shawl = 20-30 JOD
Drinking water from taps in Jordan can be safe, depending on where you are. It's considered safe to drink water from modern hotels that have filtered water but perhaps not so from smaller establishments and in rural areas. For environmental reasons, try to use a refillable water bottle rather than buying bottled water. Peel fruit before eating and avoid ice in drinks.
Major credit cards are widely accepted by stores in Jordan. Smaller cafes and shops may not accept credit cards so ensure you carry enough cash to cover small purchases.
ATMs are common in Jordan's main cities so finding one won't be a problem. Rural and remote areas typically will have less ATMs so be sure to carry enough cash for purchases when away from the city.
Absolutely. All passengers travelling with Intrepid are required to purchase travel insurance before the start of their trip. Your travel insurance details will be recorded by your leader on the first day of the trip. Due to the varying nature, availability and cost of health care around the world, travel insurance is very much an essential and necessary part of every journey.
For more information on insurance, please go to: Travel Insurance
Please note these dates are for 2017. For a current list of public holidays in Jordan go to: http://www.worldtravelguide.net/jordan/public-holidays
Intrepid is committed to travelling in a way that is respectful of local people, their culture, local economies and the environment. It's important to remember that what may be acceptable behaviour, dress and language in your own country, may not be appropriate in another. Please keep this in mind while travelling.
1. Be considerate of Jordan's customs, traditions, religion and culture.
2. Please ask and receive permission before taking photos of people, including children.
3. For environmental reasons, try to avoid buying bottled water. Fill a reusable water bottle or canteen with filtered water instead.
4. Ramadan is the fasting month for all Muslims. During this month no food, drink or smoking is permitted during daylight hours. While non-Muslims aren't expected to fast, it's recommended to try to avoid eating, drinking or smoking in public during daylight hours.
5. Refrain from touching or interfering with ancient monuments, relics or historic sites.
6. Learn some local language and don't be afraid to use it. Simple greetings will help break the ice.
7. Shop for locally made products. Supporting local artisans helps keep traditional crafts alive.
8. Ask permission and remove your shoes before entering a place of worship.
9. Dress modestly and respectfully. Shoulders to knees should be covered, especially when entering places of worship.
10. Always dispose of litter thoughtfully, including cigarette butts.


text:
Sorry I don't have a before shot, but just imagine an old rough chair with an orange vinyl seat. Yuchh!!
I sanded it and applied 4 coats of paint. I painted the lower rungs in gold and also the hand-drawn little men on the back. I then reupholstered the seat with fabric I had left from my bed quilt project (picture included) and put it all together. It fits into our bedroom just perfectly and makes a good extra chair for company.


text:
Christian Finnegan
featuring MadDog from Sirius Radio / Nate Bargatze
Friday, May 03, 2013 11:00 PM EDT
EastVille Comedy Club, New York, NY
Purchase Tickets
Additional Information
Christian is best known for playing 'Chad' in the hilariously memorable "Mad Real World" sketch on the Chappelle Show. He also stars alongside Ice Cube in the TBS sitcom Are We There Yet. Christian is also a regular on VH1's Best Week Ever, Last Call with Carson Daly and had his own Comedy Central Presents Special.
Nate is best known for his numerous appearances on Late Night with Conan O'Brien. Nate's also been featured on Comedy Central, and CMT's Comedy Stage.
Maddog is one of the most unique comedians in the country. His comedy is high energy, smart, and quirky! Maddog's crowd interactive style unites the audience while they gasp with laughter. Maddog has made appearances on the BBC Network and Sirius Radio.
All ages welcome. There's a 2 drink minimum per person. Line-up subject to change. Arrive 30 mins before showtime as seating is on a first-come basis. Those arriving late are not guaranteed seats. If reservations are missed, they can be rescheduled without penalty.


text:
JCPS sets up hotline for back to school transportation questions
JCPS sets up hotline for back to school transportation questions
LOUISVILLE, Ky. —
Jefferson County Public School students return to the classroom this week, and the district has opened a hotline for anyone with questions about transportation.
Superintendent Donna Hargens was among those answering the phones Sunday.
The hotline will be in operation over the next four days.
Anyone with questions cal call 502-485-RIDE (7433).
The hotline is open at the following times:
- Monday - 7:30 a.m. to 4:30 p.m.
- Tuesday - 7:30 a.m. to 7 p.m.
- Wednesday and Thursday - 6 a.m. to 6 p.m.
The first day of school for JCPS students is Wednesday.


text:
Friday, February 28, 2014
A Delta flight takes off; the airline has announced that starting Jan. 1, 2015, it will reward passengers for the amount they spend on tickets, not the number of miles they fly. The change to Delta's SkyMiles program will be great for people who buy expensive tickets in first-class, but bad for vacationers who shop for the cheapest fare.
Photography home | Most viewed photos | Purchase photos | Video home
© 2014 The Seattle Times Company


text:
The oil and gas industry drove the economies of some of the fastest-growing states, including Texas, in 2012.
Oil and gas gave Texas' economy a "significant boost" last year, helping its real gross domestic product — the total value of economic activity adjusted for inflation — rise 4.8 percent, said Clifford Woodruff, an economist of the U.S. Bureau of Economic Analysis. Texas ranked No. 2 nationally.
Texas saw more diversified growth than No. 1 North Dakota, said Jason Frederick, a senior economist for BBVA Compass bank. North Dakota saw 13.4 percent growth in 2012 — almost entirely from oil and gas exploration. That industry also benefited West Virginia, which was among the top 10 states with 3.3 percent growth.
Of Texas' 4.8 percent real GDP growth last year, 1.1 percent came from durable-goods manufacturing; 1 percent from oil and gas extraction and support services; 0.8 percent from wholesale and retail trade; and the rest from information technology, financial services and real estate, according to Frederick's analysis of the bureau's data.
Nationally, durable-goods manufacturing, financial services and wholesale trade were the main drivers of last year's 2.2 percent real GDP growth. Connecticut was the only state that saw a decline (0.1 percent).
This year, economists expect slightly slower growth for Texas and the nation.
Real estate made a "small contribution" to Texas' economic growth last year, but Frederick expects that to change this year with the housing recovery in full swing.
"Texas is seeing a slowdown of manufacturing activity and oil and gas extraction activity in terms of hiring … but we expect a pickup in the real estate sector," he said. "We still see a lot of strength on the horizon for Texas."
Frederick's 2013 estimates for real GDP growth are 4.3 percent in Texas and 1.8 percent nationally.
Economists' consensus forecast for U.S. real GDP growth this year is about 2.4 percent.
Follow Sheryl Jean on Twitter at @SherylJeanDMN.


text:
Written on: 10/08/2014 by JimenaMcDowell (1 review written)
So I wait just over 2 weeks and after hearing nothing I go in to find out where my glasses are. "Oh they are here" says he. "We have the wrong phone number for you so couldn't contact you." he continues. Obviously Tesco have never heard of the postman. Anyway, try the glasses on, they are sitting at an angle, he tries to persuade me to take them, I'm having none of it. The sunglasses do fit though and he tries to persuade me to take those. No, I paid for both, I want both. So another two week wait and this time the glasses are straight. Profuse apologies offered and the promise of a voucher for my inconvenience. Yes you guessed right, of course the voucher never appeared. I had broken my previous pair so needed glasses desperately as I drive for a living and can't drive without my glasses. So thanks Tesco, I lost a lot of work. Needless to say I won't be back. One word sums up the whole experience. Shoddy!


text:
New YorkParty Crasher
A Look Back At The Top NYC Parties Of 2014
From the Four Seasons to the Brooklyn Night Bazaar, from late-night bashes with the Purple crew to cocktail parties with Beyonce, 2014 was a big year in events. We take a look back at the Girls premiere, the Met Ball, the Time 100 Gala, and 22 more of the most exclusive, most stylish, and most fun-filled parties of the year!
[Allegra Versace, Lady Gaga, Donatella Versace by Billy Farrell/BFAnyc.com via @gagafan1982] [Cara Delevingne, Kate Upton, Lily Aldridge, Joan Smalls by David X Prutting/BFAnyc.com via @thestandard][Jay Z, Beyonce by Matteo Prandoni/BFAnyc.com via @bfa_nyc]
OMGamfAR New York Gala 2014New York Observer Redesign Launch PartyThe Hollywood Reporter's 35 Most Powerful People in Media2014 Chanel Tribeca Film Festival Dinner
15th Annual Free Arts Auction Celebrating Scott Campbellhosted by Marc Jacobs & Robert Duffy2014 Met BallPioneer Works Village FêteHarry Josh's Pre-Met Ball Party2014 CFDA Fashion Awards2014 MoMA Party in the GardenVeuve Clicquot Celebrates Stella McCartney's Spring 2015 Collection PresentationFashion Group International's 31st Annual Night of Stars2014 Met Ball After-PartyGuggenheim's International Gala Pre-Party2014 American Museum Of Natural History GalaIs That Blood?" With The Byrne NoticeNY Cult & Travis BassChanel Dinner Celebrating Baz Luhrmann's 'No.5' Campaign FilmHarper's BAZAAR Celebrate ICONS by Carine Roitfeld2014 Milk Holiday PartyThe 2014 Armory PartyPurple Party with TheoryHBO with The Cinema Society Host the Season 3 Premiere of "Girls"Project Perpetual Dinner & AuctionTopshop 5th Avenue Flagship OpeningBest NYC parties 2014


text:
* Q1 revenue slightly below Street View
* Q1 profit, ex items, of 57 cents, matches Street view
* Shares fall 4.4 percent
(Adds profit, forecasts, share decline)
BOSTON, March 19 (Reuters) - Adobe Systems Inc (ADBE.O), maker of Photoshop and Acrobat software, said revenue growth slowed as sales declined ahead of major upgrades to the company's Creative Suite line of digital media programs later this year.
Revenue rose 1.7 percent to $1.045 billion in its fiscal first quarter ended March 2, slightly below the $1.054 billion average forecast of analysts polled by Thomson Reuters I/B/E/S.
The company had predicted the sales slowdown in December, when it disclosed that fourth-quarter revenue surged 14 percent.
The software maker also reported that it had a first-quarter profit, excluding one-time items, of 57 cents per share, matching the average analyst forecast.
Adobe released its results as analysts are increasingly concerned about the company's plans to launch a Web-based subscription service known as Creative Cloud this year. The company is also preparing a major upgrade to its flagship Creative Suite line of design programs, CS6, which include new versions of widely used design titles such as Photoshop, Illustrator, InDesign, Flash and Dreamweaver.
Adobe's sales typically surge after a Creative Suite upgrade, but analysts have said the upswing might be smaller than in the past because customers who switch to the new service will no longer need to buy their software up front. Instead they will enter into long-term subscription agreements that allow them to rent the software and make lower initial payments. They will get extra features such as document storage at Adobe data centers.
Adobe said it expects to post second-quarter revenue of $1.090 billion to $1.140 billion, compared with the average analyst forecast of $1.1 billion.
It forecast second-quarter profit, excluding items, of 57 to 61 cents per share, compared to the Street view of 60 cents.
Shares of Adobe closed at $34.51 on Nasdaq and fell 4.4 percent to $33.00 in extended trading.
(Reporting By Jim Finkle; Editing by Richard Chang)
((email@example.com)(+1 617-856-4344)(Reuters Messaging: email@example.com)) Keywords: ADOBE/
C Reuters 2012. All rights reserved. Republication or redistribution of Reuters content, including by caching, framing, or similar means, is expressly prohibited without the prior written consent of Reuters. Reuters and the Reuters sphere logo are registered trademarks and trademarks of the Reuters group of companies around the world.


text:
San Francisco police have arrested one person and are looking for another in an early Friday morning traffic stop that escalated into a chase with gunshots fired and a dramatic crash.
Around 2 a.m., police tried to stop a white Cadillac for a traffic violation at Eddy and Laguna streets, but the driver fled south on Laguna, police said.
As the Cadillac sped off, someone in the car fired a gun back at police, then ran a red light at the intersection of Eddy and Franklin Streets where the car was struck by a taxicab, police said.
After the crash, both suspects got out of the car and ran away.
Police said the officers were able to arrest one suspect, but the other is still missing, police said.
The taxicab driver sustained non-life-threatening injuries. He was the only one injured, police said.


text:
While there are several options available in the world of classic gaming digital distribution, GOG.com is looking to break onto this scene with some great outlooks on the possibilities of such a service. GOG stands for "Good Old Games" and is touting cheap, DRM-free downloads coming this September, with a beta planned to launch August 1.{ad}
Price points for the games are listed between $5.99 and $9.99, and with promises of no DRM, infinite downloads once a game is paid for and games modernized to work on Vista and XP, the only question left is how expansive and deep is the library going to be?
So far, GOG has confirmed deals with Interplay and Codemasters guaranteeing titles like Fallout and Freespace 2 for the service, but the success of the service will clearly depend on how many other publishers they have on board. GOG is eventually aiming for a comprehensive catalogue of titles from the last three decades, and would certainly make it a potent gaming destination if they accomplish this.
Adam Oldakowski, Managing Director of GOG.com said:
Our main goal is to create a user-friendly site with the best classic PC games for a price that might be considered impossible to achieve … The people behind GOG.com are gamers and we all know how difficult it is to find a lot of classic games. So we've started building a great games catalogue, gotten rid of the copy protection that gamers hate so much, optimized the games to work on modern operating systems, and made them cheap enough that piracy seems like a rip-off. It's so easy to buy, download and install a game and then get deeply involved in the community; we're very confident that gamers will absolutely love the site.
Certainly a great amount of promises to deliver, but I get the sense that this is truly a labor of love on the part of the GOG team, and hope they can bring this vision to life.
Read more at Good Old Games


text:
Growth Whitepapers
This case study looks at how Maum Golf in South Korea partners with Dell OEM Solutions to reach its goals of expansion into new markets and grow their market share from 20 percent, to more than 30 percent by the end of 2015.
Successful businesses are empowering their employees to complete vital business transactions any time of day or night from anywhere. Mobility is transforming sales processes, optimizing customer visits, speeding sales cycles, and improving customer satisfaction. Read this paper to learn how to increase productivity and competiveness with secure mobility.
The market for integrated systems is a key growth area for data centre hardware infrastructure. This report sizes the market and profiles early leaders in this important and emerging area. • The integrated systems market is growing, with revenue increasing 53.7% year on year. • Large enterprises are currently the key customers, while the small business segment is underserved. • There is significant opportunity for overall segment growth
This whitepaper will explain how to grow your business by sharing enterprise data and services via application programming interfaces (APIs).
• Open APIs, once used only by leading technology companies such as Amazon and Facebook, have become much more prevalent • Open APIs are projected to reach 30,000 by 2016, compared to less than 600 in 2007 • A well thought-out open API strategy can drive innovation and help you compete in today's business environment.
This paper discusses: • The growing challenge of maintaining information security in today's evolving enterprise environment • Key advantages of desktop virtualization as an inherently more secure computing architecture • The top ten benefits of using desktop virtualization to strengthen information security • And how you can regain control and reduce risk without sacrificing business productivity and growth
Pure Storage set out with a simple mission: to create a purpose-built storage array that overcomes these barriers. The result is the Pure Storage FlashArray and its tightly-coupled software, the Purity Operating Environment. When compared to a disk array, the FlashArray is: - 10X faster (on both IOPS and latency); - 10X more efficient in power, space, and cooling; - More reliable on enterprise workloads; - So simple that it installs in minutes; and - Less costly than the $5 per GB that is the going rate for performance disk.


text:
I have few questions and would be happy if anybody from Intel associated with Perceptual Computing Challenge can answer it!
1. Is there any limit of number of entries that I could submit? I have submitted three entries so far. Are the prizes given to par contestant or par submission? Should each entry be submitted through different accounts of my team mates or is it fine to submit all the entries through a single ID?
2. Can we update our dropbox folder after submission? In all my entries I had submitted the source code folder with executable. But I feel making an installer is also important. People can just download the installer and try the demo when they will be made public. My question is : is it allowed to make changes in dropbox folder after submit button is clicked? I also want to add the installers.
I would really appriciate the answer.


text:
« Random thoughts |
| Bank holiday... »
The post title says it all really - The Cold has gone and I'm feeling more optimistic!
I have lovely scented freesias and Madam is happily occupied guarding my socks.
Posted at 05:17 PM in plants, Wibbo's World | Permalink
Can't beat freesias
Posted by:
David John Hulattt |
Thursday, April 10, 2014 at 03:48 AM
Lovely Freesias
Julie xxxxxxxx
Posted by:
Julie |
Thursday, April 10, 2014 at 08:07 AM
Love the sock guarding kitty.
Glad to read you are on the mend xx
Posted by:
Peri |
Thursday, April 10, 2014 at 08:09 AM
Not only can you enjoy the sight of them, but you can SMELL them too! Happy you are feeling better.
Posted by:
(Not That) Joan |
Friday, April 11, 2014 at 09:28 PM
The comments to this entry are closed.


text: Sciencedaily New extinct carnivorous marsupial discovered A new species of extinct flesh-eating marsupial that terrorized Australia's drying forests about 5 million years ago has been identified from a fossil discovered in remote northwestern Queensland. The hypercarnivore is a distant and much bigger cousin of Australia's largest living, flesh-eating marsupial, the Tasmanian devil. Named Whollydooleya tomnpatrichorum,... #discovered #extinct #marsupial Tweet Source: sciencedaily.com Read More


text:
An 18-year-old food service worker who stole from several residents of a Redwood City assisted living facility was sentenced Tuesday to nine months in jail, according to the San Mateo County District Attorney's Office.
Luis Cebrero had been working at the Woodside Terrace Senior Living complex for six months when he was arrested on Oct. 8, Redwood City police reported.
Police were called to the facility at 485 Woodside Road after another employee saw Cebrero leaving a resident's room with jewelry hidden under a food tray. Under questioning, the Menlo Park resident admitted committing five prior thefts at the complex, according to the district attorney's office. Detectives searched Cebrero's home and found several items of jewelry that had been stolen.
Cebrero pleaded no contest on Nov. 19 to a felony count of residential burglary and a misdemeanor count of theft from an elder, according to the district attorney's office.
In addition to jail time, San Mateo County Superior Court Judge Craig Parsons sentenced the teenager to three years probation and ordered him to pay more than $4,000 in restitution to the victims.
Email Bonnie Eslinger at firstname.lastname@example.com; follow her at twitter.com/bonnieeslinger.


text:
Turning cold and wet...AGAIN
BRITAIN is braced for a "depressingly cold" snap next week with snow forecast as the miserable weather continues to put summer on hold.
There is also a risk of more flooding with torrential rain driven by gale- force winds.
One family had to be rescued from the roof of their car in Morpeth, Northumberland, yesterday after getting stuck in a swollen ford.
Temperatures in parts of the North are likely to sink to -5C (23F) by Tuesday with the chance of significant snowfalls in Scotland.
Although it will feel milder in the South it will be colder than normal for the time of year with overnight frosts in some areas. The grim weather is set to last at least another week with summer on hold, possibly until next month.
Jim Dale, forecaster with British Weather Services, said: "It is going to be depressingly cold in the North. The whole country is looking at temperatures well below average.
"In the North we are looking at air frosts with ground frosts likely in the South and temperatures around -2C.
It could remain unsettled certainly for the next week or so with more heavy rain expected
"We are in a period of unseasonably cold weather, more like we would expect at the beginning of March than during May." After a brief warm spell yesterday, when temperatures in Norwich hit 70F (21C), the Met Office warned torrential downpours will hit northern regions today with more rain expected next week.
Forecaster Sarah Holland said the South would be drier but, after a brief respite at the weekend, next week will see a return of the rain and colder temperatures.
"It could remain unsettled certainly for the next week or so with more heavy rain expected," she said.
The Environment Agency has issued 16 flood alerts and has warned that virtually the entire country is at risk.
May could be the wettest and coldest on record after almost the entire monthly rainfall fell in the first 10 days.


text:
RHS grad competes on the court, frets off of it
The routine interactions are often what newlywed Maggie Bauernfeind misses the most with her husband in Iraq.
"Not being able to call him when I want to, or when I need him," said Bauernfeind. "That, and just seeing everyone else and their significant others. They get to go and hug their boyfriend after a game, and it's like, 'I don't even get to call mine.' "
The Concordia women's basketball senior, a 2007 Rosemount High School graduate, married David Shaffer, her high school sweetheart, last October. Shortly after that, he left for Iraq, where he is serving as a medic in the Army.
"You have bad days and you have good days," said Bauernfeind.
"Basketball helps me keep my mind off of it and it gives me a focus. I'm dreading basketball being done, because I think it's going to be a lot harder for me."
Bauernfeind and her Concordia teammates extended their season over the weekend, beating St. Thomas in the MIAC championship game and earning a berth in the NCAA Division III tournament. Bauernfeind had 11 points and 12 rebounds in the game, her first career double-double.
"We know it's hard being away from her husband, and we can't really know exactly what she's going through," said Cobbers senior center Ali Demmer, who is also Bauernfeind's roommate. "But, we are always there to listen and give her encouragement."
Bauernfeind changed her last name to Shaffer, but she uses her maiden name for basketball "for stats and stuff, just to keep it all the same," she said.
Bauernfeind is the No. 2 scorer for the Cobbers, averaging 12.4 points per game. She recently eclipsed 1,000 career points. She said David was tracking the live stats for the game she scored her 1,000th career point.
Bauernfeind uses Skype - for video calls - and Facebook to stay connected with her husband, who is set to come home for a two-week leave in May.
"She lets it get to her when she has everything done," Demmer said. "When she has free time, she will vent to us or bake or anything like that. It gets to her, but she is really good at getting through stuff."
Bauernfeind said having a support system, like her basketball teammates, has helped.
"I know I could trust in them and they were there for me on and off the court," Bauernfeind said. "I never had to use them before for life situations."