Saturday, 18 June 2016

Cubemap Texture Arrays

So in modern graphics API's: Direct3D 11 and 12, OpenGL 4.0 and so on, we can create 2D textures, textures with multiple mipmaps, arrays of textures with multiple mipmaps, and so on. Most don't yet support arrays of 3D textures.

But one little-used combination that is supported, is a texture cube array. That's a single texture, which is an array of cubemaps, which optionally have mip levels as well.

In Direct3D 11, this involves creating a 2D texture using D3D11_TEXTURE2D_DESC struct, where arraySize is six times the number of cubemaps.

Then, when you create the shaderResourceView, you'll use a D3D11_SHADER_RESOURCE_VIEW_DESC with ViewDimension equal to D3D11_SRV_DIMENSION_TEXTURECUBEARRAY.

You'll fill in the TextureCubeArray member of that struct's union, e.g.
 SRVDesc.ViewDimension    =D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
 SRVDesc.TextureCubeArray.MipLevels  =numMips;
 SRVDesc.TextureCubeArray.MostDetailedMip =0;
 SRVDesc.TextureCubeArray.First2DArrayFace =0;
 SRVDesc.TextureCubeArray.NumCubes  =numLevels;

Thursday, 5 May 2016

Versioning SDK's with Git for builds with Jenkins

Alright I think I've finally figured out a way to build SDK's with versioning.

Git for source control, obviously.

Development happens on the "master" branch. There's a "dev" branch for experimental stuff.
About every other month, I'll create a numbered branch. I've started with 4.0 because it continues from the old versioning system.

Each numbered branch receives only bug-fixes. All feature changes go in the master branch.

Jenkins gets a list of versions to build, defined in the main Jenkins Config as an environment variable. At the moment is looks like this:


Using Jenkins' Dynamic Axis Plugin and Matrix Projects, I use this as an axis for the matrix builds. Over time, new project numbers will be added and older ones will drop off. Jenkins will add build numbers to the version numbers, so I'll end up with installers numbered 4.0.125 etc.

Because only bug-fixes go in numbered branches, higher build numbers will always be more stable. And once you've chosen a numbered branch for your project, you can stick with that number, report to us any bugs, and be confident that the fixes will go in without any new breaking changes.

And I can develop freely on the master branch without worrying about breaking the versions in use by customers.

This should work. I'm probably the last person to figure this out.

Tuesday, 26 April 2016

Using curl in Windows to download files

This downloads a file if it's newer than the one that's on your local drive:

curl -z "path\filename.lib" ftp://ftp.yoursite.com//ftppath/filename.lib -o "path\filename.lib"

The "-z" means only copy if it's newer than a specified date. But then you just put the filename, meaning that curl should use the date of that file.
If the file doesn't exist locally, you'll get a warning about "invalid date or not a file". This can be ignored.
The "-o" means download it to the local file specified (same filename as for -z), instead of just outputting it to the console.

Monday, 29 February 2016

Problem with handling HTML form checkboxes in php

php doesn't handle checkboxes properly in html forms. If you use

My Checkbox <input type="checkbox" name="my_checkbox" id="my_checkbox"'.($current_value?'checked':'').' />

You'll only get a result for isset($_REQUEST['my_checkbox']) if the box is *checked*, not if it's cleared. So you can't test for whether the box was unchecked by the user, because using !isset would be the same whether the page was just loaded, or if the form was submitted with the box unchecked by user input.

The solution from Stack Overflow:

Every checkbox generated is associated with a hidden field of the same name, placed just before the checkbox, and with a value of "0".

<input name="my_checkbox" type="hidden" value="0" />
<input name="my_checkbox" type="checkbox" value="1" />


Then isset($_REQUEST['my_checkbox']) always returns true if the box was modified, and false if the page was just loaded. And you'll always get the correct '0' or '1' value in $_REQUEST['my_checkbox'].

Thursday, 25 February 2016

How to create a plugin for Lumberyard

Lumberyard/CryEngine uses waf, a build configuration system similar to CMake.

To add a plugin project, create a subdirectory NewPlugin in dev/Code (a plugin might go in dev/Code/Sandbox/Plugins for example).

Add a wscript file to this directory, looking like this:

 
def build(bld): 
 
 bld.CryPlugin(
  target = 'NewPlugin',
   vs_filter = 'Sandbox/Plugins',
        file_list   = 'newplugin.waf_files',
  features =  ['qt'],
  includes = [
            '.',
            '..'
        ],
  use='EditorCommon'
 )
And add a file newplugin.waf_files, looking like:
{
 "NoUberFile": 
 {
  "Root":
  [
   "NewPlugin.cpp",
   "NewPlugin.h"
  ]
 }
}
Then go to dev/_WAF_/specs, and edit all.json. Add "NewPlugin" to the win_profile_modules and win_debug_modules list. Finally, recreate the solution by opening a command prompt in dev/ and running "lmbr_waf configure"

Sunday, 14 February 2016

The Three Hierarchies of C++

Lest anyone ever tell you programming isn't complicated, it occurred to me that a C++ program has three interlocking, but independent hierarchies.

  • Namespace: The name of the function, within its parent namespace and/or the class that owns it.
  • Call Stack: The parent is the calling function, the child is the callee.
  • Inheritance: The class/struct is a child of the base class.

Could we stand to lose one or two of these?

Friday, 12 February 2016

Reverting all deletes in Git, leaving file modifications in place

I asked how to do this on StackOverflow, and the answer is:

git diff --diff-filter=D --name-only | xargs git checkout

You need the "xargs": just piping the output of "diff" to "checkout" doesn't work.