openvr_test1

changeset 0:806d30b46748

OpenVR test initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 13 Apr 2016 09:39:37 +0300
parents
children 4310ced01da8
files .hgignore openvr_test1.sln openvr_test1.vcxproj openvr_test1.vcxproj.filters src/app.cc src/app.h src/main.cc
diffstat 7 files changed, 693 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Wed Apr 13 09:39:37 2016 +0300
     1.3 @@ -0,0 +1,10 @@
     1.4 +\.o$
     1.5 +\.d$
     1.6 +\.swp$
     1.7 +^test$
     1.8 +Debug/
     1.9 +Release/
    1.10 +\.sdf$
    1.11 +\.suo$
    1.12 +\.opensdf$
    1.13 +\.exe$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/openvr_test1.sln	Wed Apr 13 09:39:37 2016 +0300
     2.3 @@ -0,0 +1,22 @@
     2.4 +
     2.5 +Microsoft Visual Studio Solution File, Format Version 12.00
     2.6 +# Visual Studio 2013
     2.7 +VisualStudioVersion = 12.0.31101.0
     2.8 +MinimumVisualStudioVersion = 10.0.40219.1
     2.9 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openvr_test1", "openvr_test1.vcxproj", "{9A02CFA8-E1B4-4F9B-B63D-65D9B60E1E50}"
    2.10 +EndProject
    2.11 +Global
    2.12 +	GlobalSection(SolutionConfigurationPlatforms) = preSolution
    2.13 +		Debug|Win32 = Debug|Win32
    2.14 +		Release|Win32 = Release|Win32
    2.15 +	EndGlobalSection
    2.16 +	GlobalSection(ProjectConfigurationPlatforms) = postSolution
    2.17 +		{9A02CFA8-E1B4-4F9B-B63D-65D9B60E1E50}.Debug|Win32.ActiveCfg = Debug|Win32
    2.18 +		{9A02CFA8-E1B4-4F9B-B63D-65D9B60E1E50}.Debug|Win32.Build.0 = Debug|Win32
    2.19 +		{9A02CFA8-E1B4-4F9B-B63D-65D9B60E1E50}.Release|Win32.ActiveCfg = Release|Win32
    2.20 +		{9A02CFA8-E1B4-4F9B-B63D-65D9B60E1E50}.Release|Win32.Build.0 = Release|Win32
    2.21 +	EndGlobalSection
    2.22 +	GlobalSection(SolutionProperties) = preSolution
    2.23 +		HideSolutionNode = FALSE
    2.24 +	EndGlobalSection
    2.25 +EndGlobal
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/openvr_test1.vcxproj	Wed Apr 13 09:39:37 2016 +0300
     3.3 @@ -0,0 +1,92 @@
     3.4 +<?xml version="1.0" encoding="utf-8"?>
     3.5 +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     3.6 +  <ItemGroup Label="ProjectConfigurations">
     3.7 +    <ProjectConfiguration Include="Debug|Win32">
     3.8 +      <Configuration>Debug</Configuration>
     3.9 +      <Platform>Win32</Platform>
    3.10 +    </ProjectConfiguration>
    3.11 +    <ProjectConfiguration Include="Release|Win32">
    3.12 +      <Configuration>Release</Configuration>
    3.13 +      <Platform>Win32</Platform>
    3.14 +    </ProjectConfiguration>
    3.15 +  </ItemGroup>
    3.16 +  <PropertyGroup Label="Globals">
    3.17 +    <ProjectGuid>{9A02CFA8-E1B4-4F9B-B63D-65D9B60E1E50}</ProjectGuid>
    3.18 +    <Keyword>Win32Proj</Keyword>
    3.19 +    <RootNamespace>openvr_test1</RootNamespace>
    3.20 +  </PropertyGroup>
    3.21 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
    3.22 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    3.23 +    <ConfigurationType>Application</ConfigurationType>
    3.24 +    <UseDebugLibraries>true</UseDebugLibraries>
    3.25 +    <PlatformToolset>v120</PlatformToolset>
    3.26 +    <CharacterSet>Unicode</CharacterSet>
    3.27 +  </PropertyGroup>
    3.28 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    3.29 +    <ConfigurationType>Application</ConfigurationType>
    3.30 +    <UseDebugLibraries>false</UseDebugLibraries>
    3.31 +    <PlatformToolset>v120</PlatformToolset>
    3.32 +    <WholeProgramOptimization>true</WholeProgramOptimization>
    3.33 +    <CharacterSet>Unicode</CharacterSet>
    3.34 +  </PropertyGroup>
    3.35 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
    3.36 +  <ImportGroup Label="ExtensionSettings">
    3.37 +  </ImportGroup>
    3.38 +  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    3.39 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
    3.40 +  </ImportGroup>
    3.41 +  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    3.42 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
    3.43 +  </ImportGroup>
    3.44 +  <PropertyGroup Label="UserMacros" />
    3.45 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    3.46 +    <LinkIncremental>true</LinkIncremental>
    3.47 +  </PropertyGroup>
    3.48 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    3.49 +    <LinkIncremental>false</LinkIncremental>
    3.50 +  </PropertyGroup>
    3.51 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    3.52 +    <ClCompile>
    3.53 +      <PrecompiledHeader>
    3.54 +      </PrecompiledHeader>
    3.55 +      <WarningLevel>Level3</WarningLevel>
    3.56 +      <Optimization>Disabled</Optimization>
    3.57 +      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    3.58 +      <DisableSpecificWarnings>4305;4244</DisableSpecificWarnings>
    3.59 +    </ClCompile>
    3.60 +    <Link>
    3.61 +      <SubSystem>Console</SubSystem>
    3.62 +      <GenerateDebugInformation>true</GenerateDebugInformation>
    3.63 +      <AdditionalDependencies>opengl32.lib;glu32.lib;glew32.lib;SDL2.lib;SDL2main.lib;openvr_api.lib;libgmath.lib;%(AdditionalDependencies)</AdditionalDependencies>
    3.64 +    </Link>
    3.65 +  </ItemDefinitionGroup>
    3.66 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    3.67 +    <ClCompile>
    3.68 +      <WarningLevel>Level3</WarningLevel>
    3.69 +      <PrecompiledHeader>
    3.70 +      </PrecompiledHeader>
    3.71 +      <Optimization>MaxSpeed</Optimization>
    3.72 +      <FunctionLevelLinking>true</FunctionLevelLinking>
    3.73 +      <IntrinsicFunctions>true</IntrinsicFunctions>
    3.74 +      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    3.75 +      <DisableSpecificWarnings>4305;4244</DisableSpecificWarnings>
    3.76 +    </ClCompile>
    3.77 +    <Link>
    3.78 +      <SubSystem>Console</SubSystem>
    3.79 +      <GenerateDebugInformation>true</GenerateDebugInformation>
    3.80 +      <EnableCOMDATFolding>true</EnableCOMDATFolding>
    3.81 +      <OptimizeReferences>true</OptimizeReferences>
    3.82 +      <AdditionalDependencies>opengl32.lib;glu32.lib;glew32.lib;SDL2.lib;SDL2main.lib;openvr_api.lib;libgmath.lib;%(AdditionalDependencies)</AdditionalDependencies>
    3.83 +    </Link>
    3.84 +  </ItemDefinitionGroup>
    3.85 +  <ItemGroup>
    3.86 +    <ClCompile Include="src\app.cc" />
    3.87 +    <ClCompile Include="src\main.cc" />
    3.88 +  </ItemGroup>
    3.89 +  <ItemGroup>
    3.90 +    <ClInclude Include="src\app.h" />
    3.91 +  </ItemGroup>
    3.92 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
    3.93 +  <ImportGroup Label="ExtensionTargets">
    3.94 +  </ImportGroup>
    3.95 +</Project>
    3.96 \ No newline at end of file
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/openvr_test1.vcxproj.filters	Wed Apr 13 09:39:37 2016 +0300
     4.3 @@ -0,0 +1,30 @@
     4.4 +<?xml version="1.0" encoding="utf-8"?>
     4.5 +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     4.6 +  <ItemGroup>
     4.7 +    <Filter Include="Source Files">
     4.8 +      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
     4.9 +      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    4.10 +    </Filter>
    4.11 +    <Filter Include="Header Files">
    4.12 +      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
    4.13 +      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
    4.14 +    </Filter>
    4.15 +    <Filter Include="Resource Files">
    4.16 +      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
    4.17 +      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    4.18 +    </Filter>
    4.19 +  </ItemGroup>
    4.20 +  <ItemGroup>
    4.21 +    <ClCompile Include="src\main.cc">
    4.22 +      <Filter>Source Files</Filter>
    4.23 +    </ClCompile>
    4.24 +    <ClCompile Include="src\app.cc">
    4.25 +      <Filter>Source Files</Filter>
    4.26 +    </ClCompile>
    4.27 +  </ItemGroup>
    4.28 +  <ItemGroup>
    4.29 +    <ClInclude Include="src\app.h">
    4.30 +      <Filter>Header Files</Filter>
    4.31 +    </ClInclude>
    4.32 +  </ItemGroup>
    4.33 +</Project>
    4.34 \ No newline at end of file
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/app.cc	Wed Apr 13 09:39:37 2016 +0300
     5.3 @@ -0,0 +1,439 @@
     5.4 +#include <stdio.h>
     5.5 +#include <assert.h>
     5.6 +#include <GL/glew.h>
     5.7 +#include <openvr.h>
     5.8 +#include <gmath/gmath.h>
     5.9 +#include "app.h"
    5.10 +
    5.11 +using namespace vr;	// OpenVR namespace
    5.12 +
    5.13 +static void draw_scene();
    5.14 +static void draw_box(float xsz, float ysz, float zsz, float norm_sign);
    5.15 +static Mat4 openvr_matrix4(const HmdMatrix44_t &mat);
    5.16 +static Mat4 openvr_matrix(const HmdMatrix34_t &mat);
    5.17 +static VRTextureBounds_t openvr_tex_bounds(float umin, float vmin, float umax, float vmax);
    5.18 +static void update_rtarg(int width, int height);
    5.19 +static unsigned int next_pow2(unsigned int x);
    5.20 +static unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1);
    5.21 +
    5.22 +static int win_width, win_height;
    5.23 +
    5.24 +static unsigned int fbo, fb_tex, fb_depth;
    5.25 +static int fb_width, fb_height;
    5.26 +static int fb_tex_width, fb_tex_height;
    5.27 +
    5.28 +static unsigned int chess_tex;
    5.29 +
    5.30 +// openvr stuff
    5.31 +static IVRSystem *vrsys;
    5.32 +static IVRCompositor *vrcomp;
    5.33 +static bool vrdev_state[k_unMaxTrackedDeviceCount];
    5.34 +static TrackedDevicePose_t vrdev_pose[k_unMaxTrackedDeviceCount];
    5.35 +static Mat4 eye_matrix[2];
    5.36 +static Mat4 proj_matrix[2];
    5.37 +static Texture_t vrtex = {0, API_OpenGL, ColorSpace_Linear};
    5.38 +static VRTextureBounds_t vrtex_bounds[2];
    5.39 +
    5.40 +bool app_init()
    5.41 +{
    5.42 +	glewInit();
    5.43 +
    5.44 +	glEnable(GL_DEPTH_TEST);
    5.45 +	glEnable(GL_CULL_FACE);
    5.46 +	glEnable(GL_LIGHTING);
    5.47 +	glEnable(GL_LIGHT0);
    5.48 +	glEnable(GL_LIGHT1);
    5.49 +	glEnable(GL_NORMALIZE);
    5.50 +
    5.51 +	glClearColor(0.1, 0.1, 0.1, 1);
    5.52 +
    5.53 +	chess_tex = gen_chess_tex(1.0, 0.7, 0.4, 0.4, 0.7, 1.0);
    5.54 +
    5.55 +	// Initialize OpenVR
    5.56 +	EVRInitError vrerr;
    5.57 +	if(!(vrsys = VR_Init(&vrerr, VRApplication_Scene))) {
    5.58 +		fprintf(stderr, "failed to initialize OpenVR: %s\n",
    5.59 +			VR_GetVRInitErrorAsEnglishDescription(vrerr));
    5.60 +		return false;
    5.61 +	}
    5.62 +	if(!(vrcomp = VRCompositor())) {
    5.63 +		fprintf(stderr, "failed to initialize OpenVR compositor\n");
    5.64 +		return false;
    5.65 +	}
    5.66 +
    5.67 +	uint32_t xsz, ysz;
    5.68 +	vrsys->GetRecommendedRenderTargetSize(&xsz, &ysz);
    5.69 +	fb_width = xsz * 2;
    5.70 +	fb_height = ysz;
    5.71 +	update_rtarg(fb_width, fb_height);	// create render target
    5.72 +
    5.73 +	for(int i=0; i<2; i++) {
    5.74 +		EVREye eye = i == 0 ? Eye_Left : Eye_Right;
    5.75 +
    5.76 +		// projection matrix for each eye
    5.77 +		proj_matrix[i] = openvr_matrix4(vrsys->GetProjectionMatrix(eye, 0.5, 500.0, API_OpenGL));
    5.78 +		// eye (relative to head) matrix
    5.79 +		eye_matrix[i] = openvr_matrix(vrsys->GetEyeToHeadTransform(eye));
    5.80 +	}
    5.81 +
    5.82 +	// XXX this doesn't seem to work correctly for some reason
    5.83 +	//vrcomp->ShowMirrorWindow();
    5.84 +
    5.85 +	assert(glGetError() == GL_NO_ERROR);
    5.86 +	return true;
    5.87 +}
    5.88 +
    5.89 +void app_shutdown()
    5.90 +{
    5.91 +	// if we call VR_Shutdown while a frame is pending, we'll crash
    5.92 +	vrcomp->ClearLastSubmittedFrame();
    5.93 +	VR_Shutdown();
    5.94 +}
    5.95 +
    5.96 +static void update()
    5.97 +{
    5.98 +	// process OpenVR events (TODO: I think there are more events to handle)
    5.99 +	VREvent_t ev;
   5.100 +	while(vrsys->PollNextEvent(&ev, sizeof ev)) {
   5.101 +		switch(ev.eventType) {
   5.102 +		case VREvent_TrackedDeviceActivated:
   5.103 +			printf("Device %u activated\n", ev.trackedDeviceIndex);
   5.104 +			break;
   5.105 +
   5.106 +		case VREvent_TrackedDeviceDeactivated:
   5.107 +			printf("Device %u lost\n", ev.trackedDeviceIndex);
   5.108 +			break;
   5.109 +
   5.110 +		case VREvent_TrackedDeviceUpdated:
   5.111 +			printf("Device %u updated(?)\n", ev.trackedDeviceIndex);
   5.112 +			break;
   5.113 +		}
   5.114 +	}
   5.115 +
   5.116 +	// TODO implement controllers
   5.117 +	for(int i=0; i<k_unMaxTrackedDeviceCount; i++) {
   5.118 +		VRControllerState_t st;
   5.119 +		if(vrsys->GetControllerState(i, &st)) {
   5.120 +			// XXX ?
   5.121 +			vrdev_state[i] = st.ulButtonPressed == 0;
   5.122 +		}
   5.123 +	}
   5.124 +
   5.125 +	// this will probably block at some point... investigate further
   5.126 +	vrcomp->WaitGetPoses(vrdev_pose, k_unMaxTrackedDeviceCount, 0, 0);
   5.127 +}
   5.128 +
   5.129 +void app_draw()
   5.130 +{
   5.131 +	update();
   5.132 +
   5.133 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
   5.134 +	glClearColor(0, 0, 0, 1);
   5.135 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   5.136 +
   5.137 +	for(int i=0; i<2; i++) {
   5.138 +		EVREye eye = i == 0 ? Eye_Left : Eye_Right;
   5.139 +
   5.140 +		glViewport(i == 0 ? 0 : fb_width / 2, 0, fb_width / 2, fb_height);
   5.141 +
   5.142 +		glMatrixMode(GL_PROJECTION);
   5.143 +		glLoadMatrixf(proj_matrix[i][0]);
   5.144 +
   5.145 +		Mat4 hmd_mat = openvr_matrix(vrdev_pose[k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking);
   5.146 +		Mat4 view_mat = inverse(eye_matrix[i] * hmd_mat);
   5.147 +
   5.148 +		glMatrixMode(GL_MODELVIEW);
   5.149 +		glLoadMatrixf(view_mat[0]);
   5.150 +
   5.151 +		draw_scene();
   5.152 +		vrcomp->Submit(eye, &vrtex, vrtex_bounds + i);
   5.153 +	}
   5.154 +	/* this is supposed to tell the compositor to get on with showing the frame without waiting for
   5.155 +	 * the next WaitGetPoses call.
   5.156 +	 */
   5.157 +	vrcomp->PostPresentHandoff();
   5.158 +
   5.159 +	glUseProgram(0);
   5.160 +
   5.161 +	// render window output
   5.162 +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
   5.163 +	glViewport(0, 0, win_width, win_height);
   5.164 +
   5.165 +	glMatrixMode(GL_PROJECTION);
   5.166 +	glLoadIdentity();
   5.167 +	glMatrixMode(GL_MODELVIEW);
   5.168 +	glLoadIdentity();
   5.169 +
   5.170 +	glPushAttrib(GL_ENABLE_BIT);
   5.171 +	glBindTexture(GL_TEXTURE_2D, fb_tex);
   5.172 +	glEnable(GL_TEXTURE_2D);
   5.173 +	glDisable(GL_LIGHTING);
   5.174 +	glDisable(GL_DEPTH_TEST);
   5.175 +
   5.176 +	glBegin(GL_QUADS);
   5.177 +	float umax = (float)fb_width / fb_tex_width;
   5.178 +	float vmax = (float)fb_height / fb_tex_height;
   5.179 +	glTexCoord2f(0, 0); glVertex2f(-1, -1);
   5.180 +	glTexCoord2f(umax, 0); glVertex2f(1, -1);
   5.181 +	glTexCoord2f(umax, vmax); glVertex2f(1, 1);
   5.182 +	glTexCoord2f(0, vmax); glVertex2f(-1, 1);
   5.183 +	glEnd();
   5.184 +
   5.185 +	glPopAttrib();
   5.186 +
   5.187 +	app_swap_buffers();
   5.188 +}
   5.189 +
   5.190 +void app_reshape(int x, int y)
   5.191 +{
   5.192 +	win_width = x;
   5.193 +	win_height = y;
   5.194 +	glViewport(0, 0, x, y);
   5.195 +
   5.196 +	glMatrixMode(GL_PROJECTION);
   5.197 +	glLoadIdentity();
   5.198 +	gluPerspective(50, (float)x / (float)y, 0.5, 500.0);
   5.199 +}
   5.200 +
   5.201 +static void draw_scene(void)
   5.202 +{
   5.203 +	float grey[] = {0.8, 0.8, 0.8, 1};
   5.204 +	float col[] = {0, 0, 0, 1};
   5.205 +	float lpos[][4] = {
   5.206 +		{-8, 2, 10, 1},
   5.207 +		{0, 15, 0, 1}
   5.208 +	};
   5.209 +	float lcol[][4] = {
   5.210 +		{0.8, 0.8, 0.8, 1},
   5.211 +		{0.4, 0.3, 0.3, 1}
   5.212 +	};
   5.213 +
   5.214 +	for(int i=0; i<2; i++) {
   5.215 +		glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos[i]);
   5.216 +		glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lcol[i]);
   5.217 +	}
   5.218 +
   5.219 +	glMatrixMode(GL_MODELVIEW);
   5.220 +
   5.221 +	glPushMatrix();
   5.222 +	glTranslatef(0, 10, 0);
   5.223 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
   5.224 +	glBindTexture(GL_TEXTURE_2D, chess_tex);
   5.225 +	glEnable(GL_TEXTURE_2D);
   5.226 +	draw_box(30, 20, 30, -1.0);
   5.227 +	glDisable(GL_TEXTURE_2D);
   5.228 +	glPopMatrix();
   5.229 +
   5.230 +	for(int i=0; i<4; i++) {
   5.231 +		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
   5.232 +		glPushMatrix();
   5.233 +		glTranslatef(i & 1 ? 5 : -5, 1, i & 2 ? -5 : 5);
   5.234 +		draw_box(0.5, 2, 0.5, 1.0);
   5.235 +		glPopMatrix();
   5.236 +
   5.237 +		col[0] = i & 1 ? 1.0 : 0.3;
   5.238 +		col[1] = i == 0 ? 1.0 : 0.3;
   5.239 +		col[2] = i & 2 ? 1.0 : 0.3;
   5.240 +		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
   5.241 +
   5.242 +		glPushMatrix();
   5.243 +		if(i & 1) {
   5.244 +			glTranslatef(0, 0.25, i & 2 ? 2 : -2);
   5.245 +		} else {
   5.246 +			glTranslatef(i & 2 ? 2 : -2, 0.25, 0);
   5.247 +		}
   5.248 +		draw_box(0.5, 0.5, 0.5, 1.0);
   5.249 +		glPopMatrix();
   5.250 +	}
   5.251 +
   5.252 +	col[0] = 1;
   5.253 +	col[1] = 1;
   5.254 +	col[2] = 0.4;
   5.255 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
   5.256 +	draw_box(0.05, 1.2, 6, 1.0);
   5.257 +	draw_box(6, 1.2, 0.05, 1.0);
   5.258 +}
   5.259 +
   5.260 +static void draw_box(float xsz, float ysz, float zsz, float norm_sign)
   5.261 +{
   5.262 +	glMatrixMode(GL_MODELVIEW);
   5.263 +	glPushMatrix();
   5.264 +	glScalef(xsz * 0.5, ysz * 0.5, zsz * 0.5);
   5.265 +
   5.266 +	if(norm_sign < 0.0) {
   5.267 +		glFrontFace(GL_CW);
   5.268 +	}
   5.269 +
   5.270 +	glBegin(GL_QUADS);
   5.271 +	glNormal3f(0, 0, 1 * norm_sign);
   5.272 +	glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
   5.273 +	glTexCoord2f(1, 0); glVertex3f(1, -1, 1);
   5.274 +	glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
   5.275 +	glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
   5.276 +	glNormal3f(1 * norm_sign, 0, 0);
   5.277 +	glTexCoord2f(0, 0); glVertex3f(1, -1, 1);
   5.278 +	glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
   5.279 +	glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
   5.280 +	glTexCoord2f(0, 1); glVertex3f(1, 1, 1);
   5.281 +	glNormal3f(0, 0, -1 * norm_sign);
   5.282 +	glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
   5.283 +	glTexCoord2f(1, 0); glVertex3f(-1, -1, -1);
   5.284 +	glTexCoord2f(1, 1); glVertex3f(-1, 1, -1);
   5.285 +	glTexCoord2f(0, 1); glVertex3f(1, 1, -1);
   5.286 +	glNormal3f(-1 * norm_sign, 0, 0);
   5.287 +	glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
   5.288 +	glTexCoord2f(1, 0); glVertex3f(-1, -1, 1);
   5.289 +	glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
   5.290 +	glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
   5.291 +	glEnd();
   5.292 +	glBegin(GL_TRIANGLE_FAN);
   5.293 +	glNormal3f(0, 1 * norm_sign, 0);
   5.294 +	glTexCoord2f(0.5, 0.5); glVertex3f(0, 1, 0);
   5.295 +	glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
   5.296 +	glTexCoord2f(1, 0); glVertex3f(1, 1, 1);
   5.297 +	glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
   5.298 +	glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
   5.299 +	glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
   5.300 +	glEnd();
   5.301 +	glBegin(GL_TRIANGLE_FAN);
   5.302 +	glNormal3f(0, -1 * norm_sign, 0);
   5.303 +	glTexCoord2f(0.5, 0.5); glVertex3f(0, -1, 0);
   5.304 +	glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
   5.305 +	glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
   5.306 +	glTexCoord2f(1, 1); glVertex3f(1, -1, 1);
   5.307 +	glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
   5.308 +	glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
   5.309 +	glEnd();
   5.310 +
   5.311 +	glFrontFace(GL_CCW);
   5.312 +	glPopMatrix();
   5.313 +}
   5.314 +
   5.315 +static Mat4 openvr_matrix4(const HmdMatrix44_t &mat)
   5.316 +{
   5.317 +	return Mat4(mat.m[0][0], mat.m[1][0], mat.m[2][0], mat.m[3][0],
   5.318 +			mat.m[0][1], mat.m[1][1], mat.m[2][1], mat.m[3][1],
   5.319 +			mat.m[0][2], mat.m[1][2], mat.m[2][2], mat.m[3][2],
   5.320 +			mat.m[0][3], mat.m[1][3], mat.m[2][3], mat.m[3][3]);
   5.321 +}
   5.322 +
   5.323 +static Mat4 openvr_matrix(const HmdMatrix34_t &mat)
   5.324 +{
   5.325 +	return Mat4(mat.m[0][0], mat.m[1][0], mat.m[2][0], 0,
   5.326 +			mat.m[0][1], mat.m[1][1], mat.m[2][1], 0,
   5.327 +			mat.m[0][2], mat.m[1][2], mat.m[2][2], 0,
   5.328 +			mat.m[0][3], mat.m[1][3], mat.m[2][3], 1);
   5.329 +}
   5.330 +
   5.331 +static VRTextureBounds_t openvr_tex_bounds(float umin, float vmin, float umax, float vmax)
   5.332 +{
   5.333 +	VRTextureBounds_t res;
   5.334 +	res.uMin = umin;
   5.335 +	res.uMax = umax;
   5.336 +	res.vMin = vmin;
   5.337 +	res.vMax = vmax;
   5.338 +	return res;
   5.339 +}
   5.340 +
   5.341 +/* update_rtarg creates (and/or resizes) the render target used to draw the two stero views */
   5.342 +static void update_rtarg(int width, int height)
   5.343 +{
   5.344 +	if(!fbo) {
   5.345 +		/* if fbo does not exist, then nothing does... create every opengl object */
   5.346 +		glGenFramebuffers(1, &fbo);
   5.347 +		glGenTextures(1, &fb_tex);
   5.348 +		glGenRenderbuffers(1, &fb_depth);
   5.349 +
   5.350 +		glBindTexture(GL_TEXTURE_2D, fb_tex);
   5.351 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   5.352 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   5.353 +	}
   5.354 +
   5.355 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
   5.356 +
   5.357 +	/* calculate the next power of two in both dimensions and use that as a texture size */
   5.358 +	fb_tex_width = next_pow2(width);
   5.359 +	fb_tex_height = next_pow2(height);
   5.360 +
   5.361 +	/* create and attach the texture that will be used as a color buffer */
   5.362 +	glBindTexture(GL_TEXTURE_2D, fb_tex);
   5.363 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0,
   5.364 +			GL_RGBA, GL_UNSIGNED_BYTE, 0);
   5.365 +	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0);
   5.366 +
   5.367 +	/* create and attach the renderbuffer that will serve as our z-buffer */
   5.368 +	glBindRenderbuffer(GL_RENDERBUFFER, fb_depth);
   5.369 +	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height);
   5.370 +	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth);
   5.371 +
   5.372 +	if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
   5.373 +		fprintf(stderr, "incomplete framebuffer!\n");
   5.374 +	}
   5.375 +
   5.376 +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
   5.377 +	printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height);
   5.378 +
   5.379 +	/* update the OpenVR texture descriptors */
   5.380 +	vrtex.handle = (void*)fb_tex;
   5.381 +	float umax = (float)fb_width / fb_tex_width;
   5.382 +	float vmax = (float)fb_height / fb_tex_height;
   5.383 +	vrtex_bounds[0] = openvr_tex_bounds(0, 1.0 - vmax, 0.5 * umax, 1.0);
   5.384 +	vrtex_bounds[1] = openvr_tex_bounds(0.5 * umax, 1.0 - vmax, umax, 1.0);
   5.385 +}
   5.386 +
   5.387 +
   5.388 +void app_keyboard(int key, bool pressed)
   5.389 +{
   5.390 +	if(pressed) {
   5.391 +		switch(key) {
   5.392 +		case 27:
   5.393 +			app_quit();
   5.394 +			break;
   5.395 +
   5.396 +		case ' ':
   5.397 +		case 'r':
   5.398 +			vrsys->ResetSeatedZeroPose();
   5.399 +			break;
   5.400 +
   5.401 +		default:
   5.402 +			break;
   5.403 +		}
   5.404 +	}
   5.405 +}
   5.406 +
   5.407 +static unsigned int next_pow2(unsigned int x)
   5.408 +{
   5.409 +	x -= 1;
   5.410 +	x |= x >> 1;
   5.411 +	x |= x >> 2;
   5.412 +	x |= x >> 4;
   5.413 +	x |= x >> 8;
   5.414 +	x |= x >> 16;
   5.415 +	return x + 1;
   5.416 +}
   5.417 +
   5.418 +/* generate a chessboard texture with tiles colored (r0, g0, b0) and (r1, g1, b1) */
   5.419 +unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1)
   5.420 +{
   5.421 +	unsigned int tex;
   5.422 +	unsigned char img[8 * 8 * 3];
   5.423 +	unsigned char *pix = img;
   5.424 +
   5.425 +	for(int i=0; i<8; i++) {
   5.426 +		for(int j=0; j<8; j++) {
   5.427 +			int black = (i & 1) == (j & 1);
   5.428 +			pix[0] = (black ? r0 : r1) * 255;
   5.429 +			pix[1] = (black ? g0 : g1) * 255;
   5.430 +			pix[2] = (black ? b0 : b1) * 255;
   5.431 +			pix += 3;
   5.432 +		}
   5.433 +	}
   5.434 +
   5.435 +	glGenTextures(1, &tex);
   5.436 +	glBindTexture(GL_TEXTURE_2D, tex);
   5.437 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   5.438 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   5.439 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
   5.440 +
   5.441 +	return tex;
   5.442 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/app.h	Wed Apr 13 09:39:37 2016 +0300
     6.3 @@ -0,0 +1,15 @@
     6.4 +#ifndef APP_H_
     6.5 +#define APP_H_
     6.6 +
     6.7 +bool app_init();
     6.8 +void app_shutdown();
     6.9 +void app_draw();
    6.10 +void app_reshape(int x, int y);
    6.11 +void app_keyboard(int bn, bool pressed);
    6.12 +void app_mouse(int bn, bool pressed, int x, int y);
    6.13 +void app_motion(int x, int y);
    6.14 +
    6.15 +void app_swap_buffers();
    6.16 +void app_quit();
    6.17 +
    6.18 +#endif	// APP_H_
    6.19 \ No newline at end of file
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/main.cc	Wed Apr 13 09:39:37 2016 +0300
     7.3 @@ -0,0 +1,85 @@
     7.4 +#include <stdio.h>
     7.5 +#include <stdlib.h>
     7.6 +#include <assert.h>
     7.7 +#include <SDL2/SDL.h>
     7.8 +#include <GL/glew.h>
     7.9 +#include "app.h"
    7.10 +
    7.11 +static bool handle_event(SDL_Event *ev);
    7.12 +
    7.13 +static SDL_Window *win;
    7.14 +static SDL_GLContext ctx;
    7.15 +static bool quit;
    7.16 +
    7.17 +int main(int argc, char **argv)
    7.18 +{
    7.19 +	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
    7.20 +	int winx = SDL_WINDOWPOS_UNDEFINED;
    7.21 +	int winy = SDL_WINDOWPOS_UNDEFINED;
    7.22 +
    7.23 +	if(!(win = SDL_CreateWindow("OpenVR test", winx, winy, 1024, 640, SDL_WINDOW_OPENGL))) {
    7.24 +		fprintf(stderr, "failed to open window\n");
    7.25 +		return 1;
    7.26 +	}
    7.27 +	if(!(ctx = SDL_GL_CreateContext(win))) {
    7.28 +		fprintf(stderr, "failed to create OpenGL context\n");
    7.29 +		return 1;
    7.30 +	}
    7.31 +	int xsz, ysz;
    7.32 +	SDL_GetWindowSize(win, &xsz, &ysz);
    7.33 +	app_reshape(xsz, ysz);
    7.34 +
    7.35 +	if(!app_init()) {
    7.36 +		return 1;
    7.37 +	}
    7.38 +
    7.39 +	for(;;) {
    7.40 +		SDL_Event ev;
    7.41 +		while(SDL_PollEvent(&ev)) {
    7.42 +			if(!handle_event(&ev) || quit) {
    7.43 +				goto done;
    7.44 +			}
    7.45 +		}
    7.46 +
    7.47 +		app_draw();
    7.48 +		assert(glGetError() == GL_NO_ERROR);
    7.49 +	}
    7.50 +
    7.51 +done:
    7.52 +	app_shutdown();
    7.53 +	SDL_Quit();
    7.54 +	return 0;
    7.55 +}
    7.56 +
    7.57 +void app_swap_buffers()
    7.58 +{
    7.59 +	SDL_GL_SwapWindow(win);
    7.60 +}
    7.61 +
    7.62 +void app_quit()
    7.63 +{
    7.64 +	quit = true;
    7.65 +}
    7.66 +
    7.67 +static bool handle_event(SDL_Event *ev)
    7.68 +{
    7.69 +	switch(ev->type) {
    7.70 +	case SDL_QUIT:
    7.71 +		return false;
    7.72 +
    7.73 +	case SDL_KEYDOWN:
    7.74 +	case SDL_KEYUP:
    7.75 +		app_keyboard(ev->key.keysym.sym, ev->key.state == SDL_PRESSED);
    7.76 +		break;
    7.77 +
    7.78 +	case SDL_WINDOWEVENT:
    7.79 +		if(ev->window.event == SDL_WINDOWEVENT_RESIZED) {
    7.80 +			app_reshape(ev->window.data1, ev->window.data2);
    7.81 +		}
    7.82 +		break;
    7.83 +
    7.84 +	default:
    7.85 +		break;
    7.86 +	}
    7.87 +	return true;
    7.88 +}
    7.89 \ No newline at end of file