conworlds

changeset 13:283cdfa7dda2

added a crapload of code from goat3dgfx
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 24 Aug 2014 09:41:24 +0300
parents 778ed91cb7fd
children 423d4e6728cb
files Makefile conworlds.sln conworlds.vcxproj conworlds.vcxproj.filters src/assload.cc src/assload.h src/dataset.h src/dataset.inl src/game.cc src/gameopt.cc src/gameopt.h src/geom.cc src/geom.h src/light.cc src/light.h src/logger.cc src/logger.h src/main.cc src/material.cc src/material.h src/mesh.cc src/mesh.h src/object.cc src/object.h src/scene.cc src/scene.h src/shader.cc src/shader.h src/texture.cc src/texture.h src/unistate.cc src/unistate.h src/xform_node.cc src/xform_node.h vrchess.sln vrchess.vcxproj vrchess.vcxproj.filters
diffstat 37 files changed, 5398 insertions(+), 274 deletions(-) [+]
line diff
     1.1 --- a/Makefile	Sat Aug 23 12:03:29 2014 +0300
     1.2 +++ b/Makefile	Sun Aug 24 09:41:24 2014 +0300
     1.3 @@ -2,7 +2,7 @@
     1.4  ccsrc = $(wildcard src/*.cc)
     1.5  obj = $(csrc:.c=.o) $(ccsrc:.cc=.o)
     1.6  dep = $(obj:.o=.d)
     1.7 -bin = vrchess
     1.8 +bin = conworlds
     1.9  
    1.10  # comment out to disable LibOVR (oculus sdk)
    1.11  #ovr_cflags = -DUSE_LIBOVR
    1.12 @@ -13,7 +13,7 @@
    1.13  
    1.14  CFLAGS = -pedantic -Wall -g $(ovr_cflags)
    1.15  CXXFLAGS = -std=c++11 $(CFLAGS)
    1.16 -LDFLAGS = $(libgl_$(sys)) -lm -lvmath -limago $(ovr_libs)
    1.17 +LDFLAGS = $(libgl_$(sys)) -lm -lvmath -limago -lanim $(ovr_libs)
    1.18  
    1.19  libgl_unix = -lGL -lGLU -lglut -lGLEW
    1.20  libgl_mac = -framework OpenGL -framework GLUT -lGLEW
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/conworlds.sln	Sun Aug 24 09:41:24 2014 +0300
     2.3 @@ -0,0 +1,20 @@
     2.4 +
     2.5 +Microsoft Visual Studio Solution File, Format Version 12.00
     2.6 +# Visual Studio 2012
     2.7 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "conworlds", "conworlds.vcxproj", "{714906B6-FD4C-4ECC-990C-247FA46B8801}"
     2.8 +EndProject
     2.9 +Global
    2.10 +	GlobalSection(SolutionConfigurationPlatforms) = preSolution
    2.11 +		Debug|Win32 = Debug|Win32
    2.12 +		Release|Win32 = Release|Win32
    2.13 +	EndGlobalSection
    2.14 +	GlobalSection(ProjectConfigurationPlatforms) = postSolution
    2.15 +		{714906B6-FD4C-4ECC-990C-247FA46B8801}.Debug|Win32.ActiveCfg = Debug|Win32
    2.16 +		{714906B6-FD4C-4ECC-990C-247FA46B8801}.Debug|Win32.Build.0 = Debug|Win32
    2.17 +		{714906B6-FD4C-4ECC-990C-247FA46B8801}.Release|Win32.ActiveCfg = Release|Win32
    2.18 +		{714906B6-FD4C-4ECC-990C-247FA46B8801}.Release|Win32.Build.0 = Release|Win32
    2.19 +	EndGlobalSection
    2.20 +	GlobalSection(SolutionProperties) = preSolution
    2.21 +		HideSolutionNode = FALSE
    2.22 +	EndGlobalSection
    2.23 +EndGlobal
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/conworlds.vcxproj	Sun Aug 24 09:41:24 2014 +0300
     3.3 @@ -0,0 +1,117 @@
     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>{714906B6-FD4C-4ECC-990C-247FA46B8801}</ProjectGuid>
    3.18 +    <Keyword>Win32Proj</Keyword>
    3.19 +    <RootNamespace>conworlds</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>MultiByte</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>false</WholeProgramOptimization>
    3.33 +    <CharacterSet>MultiByte</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;%(PreprocessorDefinitions);USE_LIBOVR</PreprocessorDefinitions>
    3.58 +      <DisableSpecificWarnings>4996;4244;4305</DisableSpecificWarnings>
    3.59 +      <AdditionalIncludeDirectories>$(SolutionDir)\src</AdditionalIncludeDirectories>
    3.60 +    </ClCompile>
    3.61 +    <Link>
    3.62 +      <SubSystem>Console</SubSystem>
    3.63 +      <GenerateDebugInformation>true</GenerateDebugInformation>
    3.64 +      <AdditionalDependencies>opengl32.lib;freeglutd.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;libovrd.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
    3.65 +    </Link>
    3.66 +  </ItemDefinitionGroup>
    3.67 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    3.68 +    <ClCompile>
    3.69 +      <WarningLevel>Level3</WarningLevel>
    3.70 +      <PrecompiledHeader>
    3.71 +      </PrecompiledHeader>
    3.72 +      <Optimization>MaxSpeed</Optimization>
    3.73 +      <FunctionLevelLinking>true</FunctionLevelLinking>
    3.74 +      <IntrinsicFunctions>true</IntrinsicFunctions>
    3.75 +      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);USE_LIBOVR</PreprocessorDefinitions>
    3.76 +      <DisableSpecificWarnings>4996;4244;4305</DisableSpecificWarnings>
    3.77 +      <AdditionalIncludeDirectories>$(SolutionDir)\src</AdditionalIncludeDirectories>
    3.78 +    </ClCompile>
    3.79 +    <Link>
    3.80 +      <SubSystem>Console</SubSystem>
    3.81 +      <GenerateDebugInformation>true</GenerateDebugInformation>
    3.82 +      <EnableCOMDATFolding>true</EnableCOMDATFolding>
    3.83 +      <OptimizeReferences>true</OptimizeReferences>
    3.84 +      <AdditionalDependencies>opengl32.lib;freeglut.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;libovr.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
    3.85 +    </Link>
    3.86 +  </ItemDefinitionGroup>
    3.87 +  <ItemGroup>
    3.88 +    <ClCompile Include="src\camera.cc" />
    3.89 +    <ClCompile Include="src\game.cc" />
    3.90 +    <ClCompile Include="src\image.cc" />
    3.91 +    <ClCompile Include="src\main.cc" />
    3.92 +    <ClCompile Include="src\opengl.cc" />
    3.93 +    <ClCompile Include="src\sdr.c" />
    3.94 +    <ClCompile Include="src\texture.cc" />
    3.95 +    <ClCompile Include="src\vr\mathutil.c" />
    3.96 +    <ClCompile Include="src\vr\opt.c" />
    3.97 +    <ClCompile Include="src\vr\rbtree.c" />
    3.98 +    <ClCompile Include="src\vr\vr.c" />
    3.99 +    <ClCompile Include="src\vr\vr_libovr.c" />
   3.100 +    <ClCompile Include="src\vr\vr_modules.c" />
   3.101 +    <ClCompile Include="src\vr\vr_null.c" />
   3.102 +    <ClCompile Include="src\vr\vr_openhmd.c" />
   3.103 +  </ItemGroup>
   3.104 +  <ItemGroup>
   3.105 +    <ClInclude Include="src\camera.h" />
   3.106 +    <ClInclude Include="src\game.h" />
   3.107 +    <ClInclude Include="src\image.h" />
   3.108 +    <ClInclude Include="src\opengl.h" />
   3.109 +    <ClInclude Include="src\sdr.h" />
   3.110 +    <ClInclude Include="src\texture.h" />
   3.111 +    <ClInclude Include="src\vr\mathutil.h" />
   3.112 +    <ClInclude Include="src\vr\opt.h" />
   3.113 +    <ClInclude Include="src\vr\rbtree.h" />
   3.114 +    <ClInclude Include="src\vr\vr.h" />
   3.115 +    <ClInclude Include="src\vr\vr_impl.h" />
   3.116 +  </ItemGroup>
   3.117 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   3.118 +  <ImportGroup Label="ExtensionTargets">
   3.119 +  </ImportGroup>
   3.120 +</Project>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/conworlds.vcxproj.filters	Sun Aug 24 09:41:24 2014 +0300
     4.3 @@ -0,0 +1,94 @@
     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="src">
     4.8 +      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
     4.9 +      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;h;inl</Extensions>
    4.10 +    </Filter>
    4.11 +    <Filter Include="src\vr">
    4.12 +      <UniqueIdentifier>{e881ab02-1a45-43f6-a15d-ee7f77256a1e}</UniqueIdentifier>
    4.13 +    </Filter>
    4.14 +  </ItemGroup>
    4.15 +  <ItemGroup>
    4.16 +    <ClCompile Include="src\main.cc">
    4.17 +      <Filter>src</Filter>
    4.18 +    </ClCompile>
    4.19 +    <ClCompile Include="src\camera.cc">
    4.20 +      <Filter>src</Filter>
    4.21 +    </ClCompile>
    4.22 +    <ClCompile Include="src\opengl.cc">
    4.23 +      <Filter>src</Filter>
    4.24 +    </ClCompile>
    4.25 +    <ClCompile Include="src\sdr.c">
    4.26 +      <Filter>src</Filter>
    4.27 +    </ClCompile>
    4.28 +    <ClCompile Include="src\game.cc">
    4.29 +      <Filter>src</Filter>
    4.30 +    </ClCompile>
    4.31 +    <ClCompile Include="src\image.cc">
    4.32 +      <Filter>src</Filter>
    4.33 +    </ClCompile>
    4.34 +    <ClCompile Include="src\texture.cc">
    4.35 +      <Filter>src</Filter>
    4.36 +    </ClCompile>
    4.37 +    <ClCompile Include="src\vr\vr.c">
    4.38 +      <Filter>src\vr</Filter>
    4.39 +    </ClCompile>
    4.40 +    <ClCompile Include="src\vr\vr_libovr.c">
    4.41 +      <Filter>src\vr</Filter>
    4.42 +    </ClCompile>
    4.43 +    <ClCompile Include="src\vr\vr_modules.c">
    4.44 +      <Filter>src\vr</Filter>
    4.45 +    </ClCompile>
    4.46 +    <ClCompile Include="src\vr\vr_null.c">
    4.47 +      <Filter>src\vr</Filter>
    4.48 +    </ClCompile>
    4.49 +    <ClCompile Include="src\vr\rbtree.c">
    4.50 +      <Filter>src\vr</Filter>
    4.51 +    </ClCompile>
    4.52 +    <ClCompile Include="src\vr\opt.c">
    4.53 +      <Filter>src\vr</Filter>
    4.54 +    </ClCompile>
    4.55 +    <ClCompile Include="src\vr\vr_openhmd.c">
    4.56 +      <Filter>src\vr</Filter>
    4.57 +    </ClCompile>
    4.58 +    <ClCompile Include="src\vr\mathutil.c">
    4.59 +      <Filter>src\vr</Filter>
    4.60 +    </ClCompile>
    4.61 +  </ItemGroup>
    4.62 +  <ItemGroup>
    4.63 +    <ClInclude Include="src\camera.h">
    4.64 +      <Filter>src</Filter>
    4.65 +    </ClInclude>
    4.66 +    <ClInclude Include="src\game.h">
    4.67 +      <Filter>src</Filter>
    4.68 +    </ClInclude>
    4.69 +    <ClInclude Include="src\image.h">
    4.70 +      <Filter>src</Filter>
    4.71 +    </ClInclude>
    4.72 +    <ClInclude Include="src\opengl.h">
    4.73 +      <Filter>src</Filter>
    4.74 +    </ClInclude>
    4.75 +    <ClInclude Include="src\sdr.h">
    4.76 +      <Filter>src</Filter>
    4.77 +    </ClInclude>
    4.78 +    <ClInclude Include="src\texture.h">
    4.79 +      <Filter>src</Filter>
    4.80 +    </ClInclude>
    4.81 +    <ClInclude Include="src\vr\vr.h">
    4.82 +      <Filter>src\vr</Filter>
    4.83 +    </ClInclude>
    4.84 +    <ClInclude Include="src\vr\vr_impl.h">
    4.85 +      <Filter>src\vr</Filter>
    4.86 +    </ClInclude>
    4.87 +    <ClInclude Include="src\vr\rbtree.h">
    4.88 +      <Filter>src\vr</Filter>
    4.89 +    </ClInclude>
    4.90 +    <ClInclude Include="src\vr\opt.h">
    4.91 +      <Filter>src\vr</Filter>
    4.92 +    </ClInclude>
    4.93 +    <ClInclude Include="src\vr\mathutil.h">
    4.94 +      <Filter>src\vr</Filter>
    4.95 +    </ClInclude>
    4.96 +  </ItemGroup>
    4.97 +</Project>
    4.98 \ No newline at end of file
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/assload.cc	Sun Aug 24 09:41:24 2014 +0300
     5.3 @@ -0,0 +1,437 @@
     5.4 +#include <stdio.h>
     5.5 +#include "assload.h"
     5.6 +#include "logger.h"
     5.7 +
     5.8 +#ifdef USE_ASSIMP
     5.9 +
    5.10 +#include <vector>
    5.11 +#include <map>
    5.12 +#include "assimp/cimport.h"
    5.13 +#include "assimp/scene.h"
    5.14 +#include "assimp/postprocess.h"
    5.15 +#include "texman.h"
    5.16 +#include "material.h"
    5.17 +#include "scene.h"
    5.18 +
    5.19 +using namespace std;
    5.20 +
    5.21 +static bool load_material(Material *mat, const aiMaterial *aimat);
    5.22 +static Object *load_node(const aiScene *aiscn, const aiNode *ainode);
    5.23 +static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh);
    5.24 +static Curve *load_curve(const aiScene *aiscn, const aiMesh *aimesh);
    5.25 +static bool load_bones(Mesh *mesh, const aiMesh *aimesh);
    5.26 +
    5.27 +static Vector3 assimp_vector(const aiVector3D &v);
    5.28 +static Quaternion assimp_quat(const aiQuaternion &q);
    5.29 +static Matrix4x4 assimp_matrix(const aiMatrix4x4 &aim);
    5.30 +static long assimp_time(const aiAnimation *anim, double aitime);
    5.31 +static void print_hierarchy(const aiNode *node);
    5.32 +
    5.33 +static map<string, Object*> obj_by_name;
    5.34 +static map<aiMesh*, Mesh*> mesh_by_aimesh;
    5.35 +
    5.36 +bool load_ass(Scene *scn, const char *fname)
    5.37 +{
    5.38 +	static bool init_done;
    5.39 +
    5.40 +	if(!init_done) {
    5.41 +		static aiLogStream log_stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT, 0);
    5.42 +		aiAttachLogStream(&log_stream);
    5.43 +		//aiEnableVerboseLogging(1);
    5.44 +		init_done = true;
    5.45 +	}
    5.46 +
    5.47 +	unsigned int proc_flags = aiProcess_JoinIdenticalVertices |
    5.48 +		aiProcess_CalcTangentSpace |
    5.49 +		aiProcess_Triangulate |
    5.50 +		aiProcess_SortByPType |
    5.51 +		aiProcess_FlipUVs;
    5.52 +
    5.53 +	const aiScene *aiscn = aiImportFile(datafile_path(fname).c_str(), proc_flags);
    5.54 +	if(!aiscn) {
    5.55 +		error_log("failed to load file: %s\n", fname);
    5.56 +		return false;
    5.57 +	}
    5.58 +
    5.59 +	info_log("NODE HIERARCHY:\n");
    5.60 +	print_hierarchy(aiscn->mRootNode);
    5.61 +	info_log("-------------------\n");
    5.62 +
    5.63 +	Vector3 root_pos, root_scaling(1.0, 1.0, 1.0);
    5.64 +	Quaternion root_rot;
    5.65 +
    5.66 +	if(aiscn->mRootNode) {
    5.67 +		Matrix4x4 root_matrix = assimp_matrix(aiscn->mRootNode->mTransformation);
    5.68 +		root_pos = root_matrix.get_translation();
    5.69 +		root_rot = root_matrix.get_rotation_quat();
    5.70 +		root_scaling = root_matrix.get_scaling();
    5.71 +	}
    5.72 +
    5.73 +	// load all meshes
    5.74 +	for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
    5.75 +		aiMesh *aimesh = aiscn->mMeshes[i];
    5.76 +		Mesh *mesh;
    5.77 +		Curve *curve;
    5.78 +
    5.79 +		switch(aimesh->mPrimitiveTypes) {
    5.80 +		case aiPrimitiveType_TRIANGLE:
    5.81 +			if((mesh = load_mesh(aiscn, aimesh))) {
    5.82 +				mesh_by_aimesh[aimesh] = mesh;
    5.83 +				scn->meshes.push_back(mesh);
    5.84 +			}
    5.85 +			break;
    5.86 +
    5.87 +		case aiPrimitiveType_LINE:
    5.88 +			if((curve = load_curve(aiscn, aimesh))) {
    5.89 +				scn->curves.push_back(curve);
    5.90 +			}
    5.91 +			break;
    5.92 +
    5.93 +		default:
    5.94 +			error_log("unsupported primitive type: %u\n", aimesh->mPrimitiveTypes);
    5.95 +			break;
    5.96 +		}
    5.97 +	}
    5.98 +
    5.99 +	// load all the nodes recursively
   5.100 +	for(unsigned int i=0; i<aiscn->mRootNode->mNumChildren; i++) {
   5.101 +		Object *obj = load_node(aiscn, aiscn->mRootNode->mChildren[i]);
   5.102 +		if(obj) {
   5.103 +			Object *dummy = new Object;
   5.104 +			dummy->set_name((string("dummyroot_") + string(obj->get_name())).c_str());
   5.105 +			dummy->set_position(root_pos);
   5.106 +			dummy->set_rotation(root_rot);
   5.107 +			dummy->set_scaling(root_scaling);
   5.108 +			dummy->add_child(obj);
   5.109 +
   5.110 +			obj = dummy;
   5.111 +			scn->objects.push_back(obj);
   5.112 +		}
   5.113 +	}
   5.114 +
   5.115 +	// load and attach the bones to the meshes
   5.116 +	for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
   5.117 +		aiMesh *aimesh = aiscn->mMeshes[i];
   5.118 +
   5.119 +		Mesh *mesh = mesh_by_aimesh[aimesh];
   5.120 +		load_bones(mesh, aimesh);
   5.121 +	}
   5.122 +
   5.123 +	obj_by_name.clear();
   5.124 +	mesh_by_aimesh.clear();
   5.125 +
   5.126 +	aiReleaseImport(aiscn);
   5.127 +	return true;
   5.128 +}
   5.129 +
   5.130 +static bool load_material(Material *mat, const aiMaterial *aimat)
   5.131 +{
   5.132 +	aiColor4D aicol;
   5.133 +	float shin, shin_str;
   5.134 +
   5.135 +	if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
   5.136 +		mat->diffuse = Vector3(aicol[0], aicol[1], aicol[2]);
   5.137 +	}
   5.138 +	if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) {
   5.139 +		mat->specular = Vector3(aicol[0], aicol[1], aicol[2]);
   5.140 +	}
   5.141 +
   5.142 +	unsigned int count = 1;
   5.143 +	if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) {
   5.144 +		shin_str = 1.0;
   5.145 +	}
   5.146 +	if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) {
   5.147 +		// XXX can't remember how I came up with this...
   5.148 +		mat->shininess = shin * shin_str * 0.0001 * 128.0;
   5.149 +	}
   5.150 +
   5.151 +	// load textures
   5.152 +	struct { int type; aiTextureType aitype; } textypes[] = {
   5.153 +		{TEX_DIFFUSE, aiTextureType_DIFFUSE},
   5.154 +		{TEX_NORMAL, aiTextureType_NORMALS},
   5.155 +		{TEX_SPECULAR, aiTextureType_SPECULAR}
   5.156 +	};
   5.157 +
   5.158 +	for(int i=0; i<sizeof textypes / sizeof *textypes; i++) {
   5.159 +		aiString aipath;
   5.160 +
   5.161 +		if(aiGetMaterialTexture(aimat, textypes[i].aitype, 0, &aipath) == 0) {
   5.162 +			char *tmp, *fname = aipath.data;
   5.163 +
   5.164 +			if((tmp = strrchr(fname, '/'))) {
   5.165 +				fname = tmp + 1;
   5.166 +			}
   5.167 +			if((tmp = strrchr(fname, '\\'))) {
   5.168 +				fname = tmp + 1;
   5.169 +			}
   5.170 +
   5.171 +			if(*fname) {
   5.172 +				mat->tex[textypes[i].type] = texset.get(fname);
   5.173 +			}
   5.174 +		}
   5.175 +	}
   5.176 +
   5.177 +	return true;
   5.178 +}
   5.179 +
   5.180 +static Object *load_node(const aiScene *aiscn, const aiNode *ainode)
   5.181 +{
   5.182 +	Object *obj = new Object;
   5.183 +	obj->set_name(ainode->mName.data);
   5.184 +
   5.185 +	if(ainode->mNumMeshes) {
   5.186 +		if(ainode->mNumMeshes > 1) {
   5.187 +			info_log("%s warning: node %s has more than one meshes (%u)\n", __FUNCTION__,
   5.188 +					ainode->mName.data, ainode->mNumMeshes);
   5.189 +		}
   5.190 +
   5.191 +		aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[0]];
   5.192 +		obj->set_mesh(mesh_by_aimesh[aimesh]);
   5.193 +
   5.194 +		// also grab the material of this mesh
   5.195 +		load_material(&obj->material, aiscn->mMaterials[aimesh->mMaterialIndex]);
   5.196 +	}
   5.197 +
   5.198 +	// if there are animations, grab the first and try to use it
   5.199 +	if(aiscn->mNumAnimations) {
   5.200 +		aiAnimation *aianim = aiscn->mAnimations[0];
   5.201 +		aiNodeAnim *ainodeanim = 0;
   5.202 +		for(unsigned int i=0; i<aianim->mNumChannels; i++) {
   5.203 +			if(strcmp(aianim->mChannels[i]->mNodeName.data, ainode->mName.data) == 0) {
   5.204 +				ainodeanim = aianim->mChannels[i];
   5.205 +				break;
   5.206 +			}
   5.207 +		}
   5.208 +
   5.209 +		if(ainodeanim) {
   5.210 +			// load all position (translation) keyframes
   5.211 +			for(unsigned int i=0; i<ainodeanim->mNumPositionKeys; i++) {
   5.212 +				Vector3 pos = assimp_vector(ainodeanim->mPositionKeys[i].mValue);
   5.213 +				long msec = assimp_time(aianim, ainodeanim->mPositionKeys[i].mTime);
   5.214 +				obj->set_position(pos, msec);
   5.215 +			}
   5.216 +
   5.217 +			// load all rotation keyframes
   5.218 +			for(unsigned int i=0; i<ainodeanim->mNumRotationKeys; i++) {
   5.219 +				Quaternion rot = assimp_quat(ainodeanim->mRotationKeys[i].mValue);
   5.220 +				if(rot.length_sq() < SMALL_NUMBER) {
   5.221 +					continue;
   5.222 +				}
   5.223 +				rot.normalize();
   5.224 +				long msec = assimp_time(aianim, ainodeanim->mRotationKeys[i].mTime);
   5.225 +				obj->set_rotation(rot, msec);
   5.226 +			}
   5.227 +
   5.228 +			// load all scaling keyframes
   5.229 +			for(unsigned int i=0; i<ainodeanim->mNumScalingKeys; i++) {
   5.230 +				Vector3 scale = assimp_vector(ainodeanim->mScalingKeys[i].mValue);
   5.231 +				long msec = assimp_time(aianim, ainodeanim->mScalingKeys[i].mTime);
   5.232 +				obj->set_scaling(scale, msec);
   5.233 +			}
   5.234 +
   5.235 +			obj->set_extrapolator(EXTRAP_REPEAT);	// loop animation
   5.236 +		} else {
   5.237 +			Matrix4x4 local_matrix = assimp_matrix(ainode->mTransformation);
   5.238 +			obj->set_local_matrix(local_matrix);
   5.239 +		}
   5.240 +	}
   5.241 +
   5.242 +	/* recurse to all children */
   5.243 +	for(unsigned int i=0; i<ainode->mNumChildren; i++) {
   5.244 +		Object *child = load_node(aiscn, ainode->mChildren[i]);
   5.245 +		if(child) {
   5.246 +			obj->add_child(child);
   5.247 +		}
   5.248 +	}
   5.249 +
   5.250 +	obj_by_name[obj->get_name()] = obj;
   5.251 +	return obj;
   5.252 +}
   5.253 +
   5.254 +static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh)
   5.255 +{
   5.256 +	Mesh *mesh = new Mesh;
   5.257 +
   5.258 +	int num_verts = aimesh->mNumVertices;
   5.259 +	int num_faces = aimesh->mNumFaces;
   5.260 +
   5.261 +	mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices);
   5.262 +
   5.263 +	if(aimesh->mNormals) {
   5.264 +		mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals);
   5.265 +	}
   5.266 +	if(aimesh->mTangents) {
   5.267 +		mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents);
   5.268 +	}
   5.269 +	if(aimesh->mTextureCoords[0]) {
   5.270 +		mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]);
   5.271 +	}
   5.272 +
   5.273 +	if(aimesh->mBones) {
   5.274 +		float *weights = mesh->set_attrib_data(MESH_ATTR_BONEWEIGHTS, 4, num_verts, 0);
   5.275 +		float *boneidx = mesh->set_attrib_data(MESH_ATTR_BONEIDX, 4, num_verts, 0);
   5.276 +
   5.277 +		memset(weights, 0, num_verts * 4 * sizeof *weights);
   5.278 +		memset(boneidx, 0, num_verts * 4 * sizeof *boneidx);
   5.279 +
   5.280 +		int *vertex_bone_count = new int[num_verts];
   5.281 +		memset(vertex_bone_count, 0, num_verts * sizeof *vertex_bone_count);
   5.282 +
   5.283 +		for(unsigned int i=0; i<aimesh->mNumBones; i++) {
   5.284 +			aiBone *aibone = aimesh->mBones[i];
   5.285 +
   5.286 +			// for every vertex affected by this bone:
   5.287 +			for(unsigned int j=0; j<aibone->mNumWeights; j++) {
   5.288 +				aiVertexWeight *aiweight = aibone->mWeights + j;
   5.289 +				int vidx = aiweight->mVertexId;
   5.290 +				int vert_boneidx = vertex_bone_count[vidx];
   5.291 +				if(vert_boneidx >= 4) {
   5.292 +					error_log("WARNING vertex with more than 4 bones found\n");
   5.293 +					continue;
   5.294 +				}
   5.295 +
   5.296 +				weights[vidx * 4 + vert_boneidx] = aiweight->mWeight;
   5.297 +				boneidx[vidx * 4 + vert_boneidx] = (float)i;
   5.298 +				vertex_bone_count[vidx]++;
   5.299 +			}
   5.300 +		}
   5.301 +
   5.302 +		delete [] vertex_bone_count;
   5.303 +
   5.304 +		// normalize weights
   5.305 +		for(int i=0; i<num_verts; i++) {
   5.306 +
   5.307 +			float wsum = 0.0f;
   5.308 +
   5.309 +			for(int j=0; j<4; j++) {
   5.310 +				wsum += weights[i * 4 + j];
   5.311 +			}
   5.312 +
   5.313 +			if(1.0 - wsum > 1e-4) {
   5.314 +				error_log("WARNING vertex with weights < 1 (%f), normalizing...\n", wsum);
   5.315 +
   5.316 +				if(wsum < 1e-6) {
   5.317 +					// this is clearly broken, let's use the first bone in full
   5.318 +					weights[i * 4] = 1.0;
   5.319 +				} else {
   5.320 +					weights[i * 4] /= wsum;
   5.321 +					weights[i * 4 + 1] /= wsum;
   5.322 +					weights[i * 4 + 2] /= wsum;
   5.323 +					weights[i * 4 + 3] /= wsum;
   5.324 +				}
   5.325 +			}
   5.326 +		}
   5.327 +	}
   5.328 +
   5.329 +	unsigned int *iptr = mesh->set_index_data(num_faces * 3);
   5.330 +	for(int i=0; i<num_faces; i++) {
   5.331 +		for(int j=0; j<3; j++) {
   5.332 +			*iptr++ = aimesh->mFaces[i].mIndices[j];
   5.333 +		}
   5.334 +	}
   5.335 +
   5.336 +	return mesh;
   5.337 +}
   5.338 +
   5.339 +static Curve *load_curve(const aiScene *aiscn, const aiMesh *aimesh)
   5.340 +{
   5.341 +	Curve *curve = new Curve;
   5.342 +
   5.343 +	for(unsigned int i=0; i<aimesh->mNumVertices; i++) {
   5.344 +		Vector3 pt = assimp_vector(aimesh->mVertices[i]);
   5.345 +		curve->add_point(pt);
   5.346 +	}
   5.347 +	info_log("loaded curve with %d points\n", aimesh->mNumVertices);
   5.348 +
   5.349 +	return curve;
   5.350 +}
   5.351 +
   5.352 +static bool load_bones(Mesh *mesh, const aiMesh *aimesh)
   5.353 +{
   5.354 +	if(!aimesh->mNumBones) {
   5.355 +		return false;
   5.356 +	}
   5.357 +
   5.358 +	for(unsigned int i=0; i<aimesh->mNumBones; i++) {
   5.359 +		aiBone *aibone = aimesh->mBones[i];
   5.360 +		Object *obj = obj_by_name[aibone->mName.data];
   5.361 +		if(!obj) {
   5.362 +			error_log("bone %s not found\n", aibone->mName.data);
   5.363 +			continue;
   5.364 +		}
   5.365 +
   5.366 +		obj->set_bone_matrix(assimp_matrix(aibone->mOffsetMatrix));
   5.367 +		mesh->add_bone(obj);
   5.368 +
   5.369 +		info_log("adding bone: %s\n", obj->get_name());
   5.370 +	}
   5.371 +
   5.372 +	return true;
   5.373 +}
   5.374 +
   5.375 +static Vector3 assimp_vector(const aiVector3D &v)
   5.376 +{
   5.377 +	return Vector3(v[0], v[1], v[2]);
   5.378 +}
   5.379 +
   5.380 +static Quaternion assimp_quat(const aiQuaternion &q)
   5.381 +{
   5.382 +	return Quaternion(q.w, Vector3(q.x, q.y, q.z));
   5.383 +}
   5.384 +
   5.385 +static Matrix4x4 assimp_matrix(const aiMatrix4x4 &aim)
   5.386 +{
   5.387 +	Matrix4x4 m;
   5.388 +	memcpy(m[0], &aim, 16 * sizeof(float));
   5.389 +	return m;
   5.390 +}
   5.391 +
   5.392 +/* convert an assimp keyframe time (ticks) into milliseconds */
   5.393 +static long assimp_time(const aiAnimation *anim, double aitime)
   5.394 +{
   5.395 +	double sec;
   5.396 +	if(anim->mTicksPerSecond < 1e-6) {
   5.397 +		// assume time is in frames?
   5.398 +		sec = aitime / 30.0;
   5.399 +	} else {
   5.400 +		sec = aitime / anim->mTicksPerSecond;
   5.401 +	}
   5.402 +	return (long)(sec * 1000.0);
   5.403 +}
   5.404 +
   5.405 +static void print_hierarchy(const aiNode *node)
   5.406 +{
   5.407 +	static int lvl;
   5.408 +	static int lvlopen[256];
   5.409 +
   5.410 +	for(int i=0; i<lvl; i++) {
   5.411 +		putchar(' ');
   5.412 +		if(lvlopen[i]) {
   5.413 +			putchar(i >= lvl - 1 ? '+' : '|');
   5.414 +		} else {
   5.415 +			putchar(i >= lvl - 1 ? '+' : ' ');
   5.416 +		}
   5.417 +	}
   5.418 +	info_log("- \"%s\"\n", node->mName.data);
   5.419 +
   5.420 +	lvlopen[lvl] = 1;
   5.421 +
   5.422 +	lvl++;
   5.423 +	for(unsigned int i=0; i<node->mNumChildren; i++) {
   5.424 +		if(i == node->mNumChildren - 1) {
   5.425 +			lvlopen[lvl - 1] = 0;
   5.426 +		}
   5.427 +		print_hierarchy(node->mChildren[i]);
   5.428 +	}
   5.429 +	lvl--;
   5.430 +}
   5.431 +
   5.432 +#else	// !defined USE_ASSIMP
   5.433 +
   5.434 +bool load_ass(Scene *scn, const char *fname)
   5.435 +{
   5.436 +	error_log("load_ass: assimp support not compiled in\n");
   5.437 +	return false;
   5.438 +}
   5.439 +
   5.440 +#endif
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/assload.h	Sun Aug 24 09:41:24 2014 +0300
     6.3 @@ -0,0 +1,9 @@
     6.4 +#ifndef ASSLOAD_H_
     6.5 +#define ASSLOAD_H_
     6.6 +
     6.7 +#include <vector>
     6.8 +#include "scene.h"
     6.9 +
    6.10 +bool load_ass(Scene *scn, const char *fname);
    6.11 +
    6.12 +#endif	// ASSLOAD_H_
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/dataset.h	Sun Aug 24 09:41:24 2014 +0300
     7.3 @@ -0,0 +1,44 @@
     7.4 +/** DataSet is a generic resource database with fast O(logn) lookups by name
     7.5 + * it can be used for texture managers, mesh managers, sound effect managers etc
     7.6 + *
     7.7 + * The constructor takes a load function and a destructor function to be called
     7.8 + * when a nonexistent resource is requested and needs to be loaded, and when
     7.9 + * the DataSet is destroyed. The destructor is optional and can be set to null
    7.10 + * if not needed.
    7.11 + *
    7.12 + * Requesting a resource works by simply calling get, example:
    7.13 + * ----------------------------------------------------------
    7.14 + * \code
    7.15 + * Texture *load_texture(const char *fname);
    7.16 + * void free_texture(Texture *tex);
    7.17 + *
    7.18 + * DataSet<Texture*> texman(load_texture, free_texture);
    7.19 + * Texture *foo = texman.get("foo.png");
    7.20 + * \endcode
    7.21 + */
    7.22 +#ifndef DATASET_H_
    7.23 +#define DATASET_H_
    7.24 +
    7.25 +#include <string>
    7.26 +#include <map>
    7.27 +
    7.28 +template <typename T>
    7.29 +class DataSet {
    7.30 +protected:
    7.31 +	mutable std::map<std::string, T> data;
    7.32 +
    7.33 +	T (*load)(const char*);
    7.34 +	void (*destroy)(T);
    7.35 +
    7.36 +public:
    7.37 +	DataSet(T (*load_func)(const char*), void (*destr_func)(T) = 0);
    7.38 +	~DataSet();
    7.39 +
    7.40 +	void clear();
    7.41 +
    7.42 +	T get(const char *name) const;
    7.43 +};
    7.44 +
    7.45 +#include "dataset.inl"
    7.46 +
    7.47 +#endif	// DATASET_H_
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/dataset.inl	Sun Aug 24 09:41:24 2014 +0300
     8.3 @@ -0,0 +1,55 @@
     8.4 +#include <stdio.h>
     8.5 +#include <string.h>
     8.6 +
     8.7 +template <typename T>
     8.8 +DataSet<T>::DataSet(T (*load_func)(const char*), void (*destr_func)(T))
     8.9 +{
    8.10 +	load = load_func;
    8.11 +	destroy = destr_func;
    8.12 +}
    8.13 +
    8.14 +template <typename T>
    8.15 +DataSet<T>::~DataSet()
    8.16 +{
    8.17 +	clear();
    8.18 +}
    8.19 +
    8.20 +template <typename T>
    8.21 +void DataSet<T>::clear()
    8.22 +{
    8.23 +	if(destroy) {
    8.24 +		typename std::map<std::string, T>::iterator it = data.begin();
    8.25 +		while(it != data.end()) {
    8.26 +			destroy(it++->second);
    8.27 +		}
    8.28 +	}
    8.29 +	data.clear();
    8.30 +}
    8.31 +
    8.32 +template <typename T>
    8.33 +T DataSet<T>::get(const char *name) const
    8.34 +{
    8.35 +	typename std::map<std::string, T>::const_iterator iter = data.find(name);
    8.36 +	if(iter != data.end()) {
    8.37 +		return iter->second;
    8.38 +	}
    8.39 +
    8.40 +	const char *fname, *slash;
    8.41 +	if((slash = strrchr(name, '/'))) {
    8.42 +		fname = slash + 1;
    8.43 +	} else {
    8.44 +		fname = name;
    8.45 +	}
    8.46 +
    8.47 +	std::string path = fname;
    8.48 +	if(path.empty()) {
    8.49 +		fprintf(stderr, "can't find data file: %s\n", name);
    8.50 +		return 0;
    8.51 +	}
    8.52 +
    8.53 +	T res = load(path.c_str());
    8.54 +	if(res) {
    8.55 +		data[name] = res;
    8.56 +	}
    8.57 +	return res;
    8.58 +}
     9.1 --- a/src/game.cc	Sat Aug 23 12:03:29 2014 +0300
     9.2 +++ b/src/game.cc	Sun Aug 24 09:41:24 2014 +0300
     9.3 @@ -1,4 +1,5 @@
     9.4  #include "game.h"
     9.5 +#include "gameopt.h"
     9.6  #include "opengl.h"
     9.7  #include "camera.h"
     9.8  #include "texture.h"
     9.9 @@ -18,11 +19,18 @@
    9.10  static FlyCamera cam;
    9.11  static Texture floor_tex;
    9.12  static bool keystate[256];
    9.13 +static float player_height = 1.68;
    9.14  
    9.15  bool game_init()
    9.16  {
    9.17 -	vr_init();
    9.18 -	//vr_use_module_named("null");
    9.19 +	if(opt.vr) {
    9.20 +		vr_init();
    9.21 +		if(opt.vr_module) {
    9.22 +			vr_use_module_named(opt.vr_module);
    9.23 +		}
    9.24 +
    9.25 +		player_height = vr_get_optf(VR_OPT_EYE_HEIGHT);
    9.26 +	}
    9.27  
    9.28  	glEnable(GL_DEPTH_TEST);
    9.29  	glEnable(GL_CULL_FACE);
    9.30 @@ -37,14 +45,16 @@
    9.31  		return false;
    9.32  	}
    9.33  
    9.34 -	cam.input_move(0, 0, 5);
    9.35 +	cam.input_move(0, player_height, 0);
    9.36  	return true;
    9.37  }
    9.38  
    9.39  void game_cleanup()
    9.40  {
    9.41  	floor_tex.destroy();
    9.42 -	vr_shutdown();
    9.43 +	if(opt.vr) {
    9.44 +		vr_shutdown();
    9.45 +	}
    9.46  
    9.47  	if(fbo) {
    9.48  		glDeleteFramebuffers(1, &fbo);
    9.49 @@ -88,24 +98,30 @@
    9.50  
    9.51  void game_render()
    9.52  {
    9.53 -	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    9.54 -	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    9.55 +	if(opt.vr) {
    9.56 +		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    9.57 +		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    9.58  
    9.59 -	glViewport(0, 0, rtwidth / 2.0, rtheight);
    9.60 -	vr_begin(VR_EYE_LEFT);
    9.61 -	game_render_eye(-1);
    9.62 -	vr_end();
    9.63 +		glViewport(0, 0, rtwidth / 2.0, rtheight);
    9.64 +		vr_begin(VR_EYE_LEFT);
    9.65 +		game_render_eye(-1);
    9.66 +		vr_end();
    9.67  
    9.68 -	glViewport(rtwidth / 2, 0, rtwidth / 2.0, rtheight);
    9.69 -	vr_begin(VR_EYE_RIGHT);
    9.70 -	game_render_eye(1);
    9.71 -	vr_end();
    9.72 +		glViewport(rtwidth / 2, 0, rtwidth / 2.0, rtheight);
    9.73 +		vr_begin(VR_EYE_RIGHT);
    9.74 +		game_render_eye(1);
    9.75 +		vr_end();
    9.76  
    9.77 -	glBindFramebuffer(GL_FRAMEBUFFER, 0);
    9.78 -	glViewport(0, 0, fb_width, fb_height);
    9.79 +		glBindFramebuffer(GL_FRAMEBUFFER, 0);
    9.80 +		glViewport(0, 0, fb_width, fb_height);
    9.81  
    9.82 -	vr_output_texture(rtarg->get_texture_id(), 0, 0, (float)rtwidth / (float)rtarg->get_width(),
    9.83 -		(float)rtheight / (float)rtarg->get_height());
    9.84 +		vr_output_texture(rtarg->get_texture_id(), 0, 0, (float)rtwidth / (float)rtarg->get_width(),
    9.85 +			(float)rtheight / (float)rtarg->get_height());
    9.86 +	} else {
    9.87 +		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    9.88 +
    9.89 +		game_render_eye(0);
    9.90 +	}
    9.91  
    9.92  	vr_swap_buffers();
    9.93  }
    9.94 @@ -218,14 +234,11 @@
    9.95  
    9.96  static void draw_scene()
    9.97  {
    9.98 -	glMatrixMode(GL_MODELVIEW);
    9.99 -	glTranslatef(0, -1.5, 0);
   9.100 -
   9.101  	float lpos[] = {-20, 30, 10, 1};
   9.102  	glLightfv(GL_LIGHT0, GL_POSITION, lpos);
   9.103  
   9.104  	glEnable(GL_TEXTURE_2D);
   9.105 -	floor_tex.bind();
   9.106 +	bind_texture(&floor_tex);
   9.107  
   9.108  	glMatrixMode(GL_TEXTURE);
   9.109  	glScalef(8, 8, 8);
   9.110 @@ -251,19 +264,19 @@
   9.111  		glNormal3f(0, 1, 1);
   9.112  		glVertex3f(-1, 0, 1);
   9.113  		glVertex3f(1, 0, 1);
   9.114 -		glVertex3f(0, 1.2, 0);
   9.115 +		glVertex3f(0, 1.75, 0);
   9.116  		glNormal3f(1, 1, 0);
   9.117  		glVertex3f(1, 0, 1);
   9.118  		glVertex3f(1, 0, -1);
   9.119 -		glVertex3f(0, 1.2, 0);
   9.120 +		glVertex3f(0, 1.75, 0);
   9.121  		glNormal3f(0, 1, -1);
   9.122  		glVertex3f(1, 0, -1);
   9.123  		glVertex3f(-1, 0, -1);
   9.124 -		glVertex3f(0, 1.2, 0);
   9.125 +		glVertex3f(0, 1.75, 0);
   9.126  		glNormal3f(-1, 1, 0);
   9.127  		glVertex3f(-1, 0, -1);
   9.128  		glVertex3f(-1, 0, 1);
   9.129 -		glVertex3f(0, 1.2, 0);
   9.130 +		glVertex3f(0, 1.75, 0);
   9.131  		glEnd();
   9.132  
   9.133  		glPopMatrix();
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/gameopt.cc	Sun Aug 24 09:41:24 2014 +0300
    10.3 @@ -0,0 +1,39 @@
    10.4 +#include <stdio.h>
    10.5 +#include <string.h>
    10.6 +#include "gameopt.h"
    10.7 +
    10.8 +GameOption opt;
    10.9 +
   10.10 +bool parse_args(int argc, char **argv)
   10.11 +{
   10.12 +	int i;
   10.13 +
   10.14 +	for(i=1; i<argc; i++) {
   10.15 +		if(argv[i][0] == '-') {
   10.16 +			if(strcmp(argv[i], "-vr") == 0) {
   10.17 +				opt.vr = true;
   10.18 +
   10.19 +			} else if(strcmp(argv[i], "-vrmodule") == 0) {
   10.20 +				opt.vr_module = argv[++i];
   10.21 +				if(strcmp(opt.vr_module, "stereo") == 0) {
   10.22 +					opt.stereo = true;
   10.23 +				}
   10.24 +
   10.25 +			} else {
   10.26 +				fprintf(stderr, "invalid option: %s\n", argv[i]);
   10.27 +				return false;
   10.28 +			}
   10.29 +		} else {
   10.30 +			fprintf(stderr, "unexpected argument: %s\n", argv[i]);
   10.31 +			return false;
   10.32 +		}
   10.33 +	}
   10.34 +	return true;
   10.35 +}
   10.36 +
   10.37 +GameOption::GameOption()
   10.38 +{
   10.39 +	vr = false;
   10.40 +	vr_module = 0;
   10.41 +	stereo = false;
   10.42 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/gameopt.h	Sun Aug 24 09:41:24 2014 +0300
    11.3 @@ -0,0 +1,16 @@
    11.4 +#ifndef GAMEOPT_H_
    11.5 +#define GAMEOPT_H_
    11.6 +
    11.7 +struct GameOption {
    11.8 +	bool vr;
    11.9 +	char *vr_module;
   11.10 +	bool stereo;
   11.11 +
   11.12 +	GameOption();
   11.13 +};
   11.14 +
   11.15 +extern GameOption opt;
   11.16 +
   11.17 +bool parse_args(int argc, char **argv);
   11.18 +
   11.19 +#endif	// GAMEOPT_H_
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/geom.cc	Sun Aug 24 09:41:24 2014 +0300
    12.3 @@ -0,0 +1,270 @@
    12.4 +#include <algorithm>
    12.5 +#include <float.h>
    12.6 +#include "geom.h"
    12.7 +#include "logger.h"
    12.8 +
    12.9 +GeomObject::~GeomObject()
   12.10 +{
   12.11 +}
   12.12 +
   12.13 +
   12.14 +Sphere::Sphere()
   12.15 +{
   12.16 +	radius = 1.0;
   12.17 +}
   12.18 +
   12.19 +Sphere::Sphere(const Vector3 &cent, float radius)
   12.20 +	: center(cent)
   12.21 +{
   12.22 +	this->radius = radius;
   12.23 +}
   12.24 +
   12.25 +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2)
   12.26 +{
   12.27 +	const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1);
   12.28 +	const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2);
   12.29 +
   12.30 +	if(!sph1 || !sph2) {
   12.31 +		error_log("Sphere::set_union: arguments must be spheres");
   12.32 +		return;
   12.33 +	}
   12.34 +
   12.35 +	float dist = (sph1->center - sph2->center).length();
   12.36 +	float surf_dist = dist - (sph1->radius + sph2->radius);
   12.37 +	float d1 = sph1->radius + surf_dist / 2.0;
   12.38 +	float d2 = sph2->radius + surf_dist / 2.0;
   12.39 +	float t = d1 / (d1 + d2);
   12.40 +
   12.41 +	if(t < 0.0) t = 0.0;
   12.42 +	if(t > 1.0) t = 1.0;
   12.43 +
   12.44 +	center = sph1->center * t + sph2->center * (1.0 - t);
   12.45 +	radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius);
   12.46 +}
   12.47 +
   12.48 +void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   12.49 +{
   12.50 +	error_log("Sphere::intersection undefined\n");
   12.51 +}
   12.52 +
   12.53 +bool Sphere::contains(const Vector3 &pt) const
   12.54 +{
   12.55 +	float dist_sq = (pt - center).length_sq();
   12.56 +	return dist_sq <= radius * radius;
   12.57 +}
   12.58 +
   12.59 +bool Sphere::intersect(const Ray &ray, HitPoint *hit) const
   12.60 +{
   12.61 +	float a = dot_product(ray.dir, ray.dir);
   12.62 +	float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) +
   12.63 +		2.0 * ray.dir.y * (ray.origin.y - center.y) +
   12.64 +		2.0 * ray.dir.z * (ray.origin.z - center.z);
   12.65 +	float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) -
   12.66 +		2.0 * dot_product(ray.origin, center) - radius * radius;
   12.67 +
   12.68 +	float discr = b * b - 4.0 * a * c;
   12.69 +	if(discr < 1e-4) {
   12.70 +		return false;
   12.71 +	}
   12.72 +
   12.73 +	float sqrt_discr = sqrt(discr);
   12.74 +	float t0 = (-b + sqrt_discr) / (2.0 * a);
   12.75 +	float t1 = (-b - sqrt_discr) / (2.0 * a);
   12.76 +
   12.77 +	if(t0 < 1e-4)
   12.78 +		t0 = t1;
   12.79 +	if(t1 < 1e-4)
   12.80 +		t1 = t0;
   12.81 +
   12.82 +	float t = t0 < t1 ? t0 : t1;
   12.83 +	if(t < 1e-4) {
   12.84 +		return false;
   12.85 +	}
   12.86 +
   12.87 +	// fill the HitPoint structure
   12.88 +	if(hit) {
   12.89 +		hit->obj = this;
   12.90 +		hit->dist = t;
   12.91 +		hit->pos = ray.origin + ray.dir * t;
   12.92 +		hit->normal = (hit->pos - center) / radius;
   12.93 +	}
   12.94 +	return true;
   12.95 +}
   12.96 +
   12.97 +
   12.98 +AABox::AABox()
   12.99 +{
  12.100 +}
  12.101 +
  12.102 +AABox::AABox(const Vector3 &vmin, const Vector3 &vmax)
  12.103 +	: min(vmin), max(vmax)
  12.104 +{
  12.105 +}
  12.106 +
  12.107 +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2)
  12.108 +{
  12.109 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
  12.110 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
  12.111 +
  12.112 +	if(!box1 || !box2) {
  12.113 +		error_log("AABox::set_union: arguments must be AABoxes too\n");
  12.114 +		return;
  12.115 +	}
  12.116 +
  12.117 +	min.x = std::min(box1->min.x, box2->min.x);
  12.118 +	min.y = std::min(box1->min.y, box2->min.y);
  12.119 +	min.z = std::min(box1->min.z, box2->min.z);
  12.120 +
  12.121 +	max.x = std::max(box1->max.x, box2->max.x);
  12.122 +	max.y = std::max(box1->max.y, box2->max.y);
  12.123 +	max.z = std::max(box1->max.z, box2->max.z);
  12.124 +}
  12.125 +
  12.126 +void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
  12.127 +{
  12.128 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
  12.129 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
  12.130 +
  12.131 +	if(!box1 || !box2) {
  12.132 +		error_log("AABox::set_intersection: arguments must be AABoxes too\n");
  12.133 +		return;
  12.134 +	}
  12.135 +
  12.136 +	for(int i=0; i<3; i++) {
  12.137 +		min[i] = std::max(box1->min[i], box2->min[i]);
  12.138 +		max[i] = std::min(box1->max[i], box2->max[i]);
  12.139 +
  12.140 +		if(max[i] < min[i]) {
  12.141 +			max[i] = min[i];
  12.142 +		}
  12.143 +	}
  12.144 +}
  12.145 +
  12.146 +bool AABox::contains(const Vector3 &pt) const
  12.147 +{
  12.148 +	return pt.x >= min.x && pt.x <= max.x &&
  12.149 +		pt.y >= min.y && pt.y <= max.y &&
  12.150 +		pt.z >= min.z && pt.z <= max.z;
  12.151 +}
  12.152 +
  12.153 +bool AABox::intersect(const Ray &ray, HitPoint *hit) const
  12.154 +{
  12.155 +	Vector3 param[2] = {min, max};
  12.156 +	Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
  12.157 +	int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
  12.158 +
  12.159 +	float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
  12.160 +	float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
  12.161 +	float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
  12.162 +	float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
  12.163 +
  12.164 +	if(tmin > tymax || tymin > tmax) {
  12.165 +		return false;
  12.166 +	}
  12.167 +	if(tymin > tmin) {
  12.168 +		tmin = tymin;
  12.169 +	}
  12.170 +	if(tymax < tmax) {
  12.171 +		tmax = tymax;
  12.172 +	}
  12.173 +
  12.174 +	float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
  12.175 +	float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
  12.176 +
  12.177 +	if(tmin > tzmax || tzmin > tmax) {
  12.178 +		return false;
  12.179 +	}
  12.180 +	if(tzmin > tmin) {
  12.181 +		tmin = tzmin;
  12.182 +	}
  12.183 +	if(tzmax < tmax) {
  12.184 +		tmax = tzmax;
  12.185 +	}
  12.186 +
  12.187 +	float t = tmin < 1e-4 ? tmax : tmin;
  12.188 +	if(t >= 1e-4) {
  12.189 +
  12.190 +		if(hit) {
  12.191 +			hit->obj = this;
  12.192 +			hit->dist = t;
  12.193 +			hit->pos = ray.origin + ray.dir * t;
  12.194 +
  12.195 +			float min_dist = FLT_MAX;
  12.196 +			Vector3 offs = min + (max - min) / 2.0;
  12.197 +			Vector3 local_hit = hit->pos - offs;
  12.198 +
  12.199 +			static const Vector3 axis[] = {
  12.200 +				Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)
  12.201 +			};
  12.202 +			//int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}};
  12.203 +
  12.204 +			for(int i=0; i<3; i++) {
  12.205 +				float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i]));
  12.206 +				if(dist < min_dist) {
  12.207 +					min_dist = dist;
  12.208 +					hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0);
  12.209 +					//hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]);
  12.210 +				}
  12.211 +			}
  12.212 +		}
  12.213 +		return true;
  12.214 +	}
  12.215 +	return false;
  12.216 +
  12.217 +}
  12.218 +
  12.219 +Plane::Plane()
  12.220 +	: normal(0.0, 1.0, 0.0)
  12.221 +{
  12.222 +}
  12.223 +
  12.224 +Plane::Plane(const Vector3 &p, const Vector3 &norm)
  12.225 +	: pt(p)
  12.226 +{
  12.227 +	normal = norm.normalized();
  12.228 +}
  12.229 +
  12.230 +Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3)
  12.231 +	: pt(p1)
  12.232 +{
  12.233 +	normal = cross_product(p2 - p1, p3 - p1).normalized();
  12.234 +}
  12.235 +
  12.236 +Plane::Plane(const Vector3 &normal, float dist)
  12.237 +{
  12.238 +	this->normal = normal.normalized();
  12.239 +	pt = this->normal * dist;
  12.240 +}
  12.241 +
  12.242 +void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2)
  12.243 +{
  12.244 +	error_log("Plane::set_union undefined\n");
  12.245 +}
  12.246 +
  12.247 +void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
  12.248 +{
  12.249 +	error_log("Plane::set_intersection undefined\n");
  12.250 +}
  12.251 +
  12.252 +bool Plane::contains(const Vector3 &pt) const
  12.253 +{
  12.254 +	return false;	// TODO: maybe define containment as half-space containment?
  12.255 +}
  12.256 +
  12.257 +bool Plane::intersect(const Ray &ray, HitPoint *hit) const
  12.258 +{
  12.259 +	float ndotdir = dot_product(normal, ray.dir);
  12.260 +	if(fabs(ndotdir) < 1e-4) {
  12.261 +		return false;
  12.262 +	}
  12.263 +
  12.264 +	if(hit) {
  12.265 +		Vector3 ptdir = pt - ray.origin;
  12.266 +		float t = dot_product(normal, ptdir) / ndotdir;
  12.267 +
  12.268 +		hit->pos = ray.origin + ray.dir * t;
  12.269 +		hit->normal = normal;
  12.270 +		hit->obj = this;
  12.271 +	}
  12.272 +	return true;
  12.273 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/geom.h	Sun Aug 24 09:41:24 2014 +0300
    13.3 @@ -0,0 +1,71 @@
    13.4 +#ifndef GEOMOBJ_H_
    13.5 +#define GEOMOBJ_H_
    13.6 +
    13.7 +#include "vmath/vmath.h"
    13.8 +
    13.9 +class GeomObject;
   13.10 +
   13.11 +struct HitPoint {
   13.12 +	float dist;				//< parametric distance along the ray
   13.13 +	Vector3 pos;			//< position of intersection (orig + dir * dist)
   13.14 +	Vector3 normal;			//< normal at the point of intersection
   13.15 +	const void *obj;		//< pointer to the intersected object
   13.16 +};
   13.17 +
   13.18 +class GeomObject {
   13.19 +public:
   13.20 +	virtual ~GeomObject();
   13.21 +
   13.22 +	virtual void set_union(const GeomObject *obj1, const GeomObject *obj2) = 0;
   13.23 +	virtual void set_intersection(const GeomObject *obj1, const GeomObject *obj2) = 0;
   13.24 +
   13.25 +	virtual bool contains(const Vector3 &pt) const = 0;
   13.26 +	virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0;
   13.27 +};
   13.28 +
   13.29 +class Sphere : public GeomObject {
   13.30 +public:
   13.31 +	Vector3 center;
   13.32 +	float radius;
   13.33 +
   13.34 +	Sphere();
   13.35 +	Sphere(const Vector3 &center, float radius);
   13.36 +
   13.37 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
   13.38 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
   13.39 +
   13.40 +	bool contains(const Vector3 &pt) const;
   13.41 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   13.42 +};
   13.43 +
   13.44 +class AABox : public GeomObject {
   13.45 +public:
   13.46 +	Vector3 min, max;
   13.47 +
   13.48 +	AABox();
   13.49 +	AABox(const Vector3 &min, const Vector3 &max);
   13.50 +
   13.51 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
   13.52 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
   13.53 +
   13.54 +	bool contains(const Vector3 &pt) const;
   13.55 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   13.56 +};
   13.57 +
   13.58 +class Plane : public GeomObject {
   13.59 +public:
   13.60 +	Vector3 pt, normal;
   13.61 +
   13.62 +	Plane();
   13.63 +	Plane(const Vector3 &pt, const Vector3 &normal);
   13.64 +	Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3);
   13.65 +	Plane(const Vector3 &normal, float dist);
   13.66 +
   13.67 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
   13.68 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
   13.69 +
   13.70 +	bool contains(const Vector3 &pt) const;
   13.71 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   13.72 +};
   13.73 +
   13.74 +#endif	// GEOMOBJ_H_
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/light.cc	Sun Aug 24 09:41:24 2014 +0300
    14.3 @@ -0,0 +1,36 @@
    14.4 +#include "light.h"
    14.5 +
    14.6 +Light::Light()
    14.7 +{
    14.8 +	cast_shadows = false;
    14.9 +}
   14.10 +
   14.11 +void Light::set_color(const Vector3 &color)
   14.12 +{
   14.13 +	this->color = color;
   14.14 +}
   14.15 +
   14.16 +const Vector3 &Light::get_color() const
   14.17 +{
   14.18 +	return color;
   14.19 +}
   14.20 +
   14.21 +void Light::set_attenuation(const Vector3 &att)
   14.22 +{
   14.23 +	attenuation = att;
   14.24 +}
   14.25 +
   14.26 +const Vector3 &Light::get_attenuation() const
   14.27 +{
   14.28 +	return attenuation;
   14.29 +}
   14.30 +
   14.31 +void Light::set_shadow_caster(bool s)
   14.32 +{
   14.33 +	cast_shadows = s;
   14.34 +}
   14.35 +
   14.36 +bool Light::is_shadow_caster() const
   14.37 +{
   14.38 +	return cast_shadows;
   14.39 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/light.h	Sun Aug 24 09:41:24 2014 +0300
    15.3 @@ -0,0 +1,27 @@
    15.4 +#ifndef GOATGFX_LIGHT_H_
    15.5 +#define GOATGFX_LIGHT_H_
    15.6 +
    15.7 +#include "xform_node.h"
    15.8 +
    15.9 +
   15.10 +class Light : public XFormNode {
   15.11 +private:
   15.12 +	Vector3 color;
   15.13 +	Vector3 attenuation;
   15.14 +
   15.15 +	bool cast_shadows;
   15.16 +
   15.17 +public:
   15.18 +	Light();
   15.19 +
   15.20 +	void set_color(const Vector3 &color);
   15.21 +	const Vector3 &get_color() const;
   15.22 +
   15.23 +	void set_attenuation(const Vector3 &att);
   15.24 +	const Vector3 &get_attenuation() const;
   15.25 +
   15.26 +	void set_shadow_caster(bool s);
   15.27 +	bool is_shadow_caster() const;
   15.28 +};
   15.29 +
   15.30 +#endif	// GOATGFX_LIGHT_H_
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/logger.cc	Sun Aug 24 09:41:24 2014 +0300
    16.3 @@ -0,0 +1,118 @@
    16.4 +#include <stdio.h>
    16.5 +#include <stdarg.h>
    16.6 +#include "logger.h"
    16.7 +
    16.8 +#if defined(unix) || defined(__unix__) || defined(__APPLE__)
    16.9 +#include <unistd.h>
   16.10 +#elif defined(WIN32)
   16.11 +#include <windows.h>
   16.12 +#endif
   16.13 +
   16.14 +enum { LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL, LOG_DEBUG };
   16.15 +
   16.16 +static int typecolor(int type);
   16.17 +
   16.18 +static FILE *fp = stdout;
   16.19 +
   16.20 +static void logmsg(int type, const char *fmt, va_list ap)
   16.21 +{
   16.22 +#if defined(unix) || defined(__unix__) || (defined(__APPLE__) && !defined(TARGET_IPHONE))
   16.23 +	if(isatty(fileno(fp)) && type != LOG_INFO) {
   16.24 +		int c = typecolor(type);
   16.25 +		fprintf(fp, "\033[%dm", c);
   16.26 +		vfprintf(fp, fmt, ap);
   16.27 +		fprintf(fp, "\033[0m");
   16.28 +	} else
   16.29 +#endif
   16.30 +	{
   16.31 +		vfprintf(fp, fmt, ap);
   16.32 +	}
   16.33 +	if(type == LOG_ERROR || type == LOG_FATAL || type == LOG_DEBUG) {
   16.34 +		fflush(fp);
   16.35 +	}
   16.36 +
   16.37 +#ifdef WIN32
   16.38 +	if(type == LOG_FATAL) {
   16.39 +		static char msgbuf[1024];
   16.40 +		vsnprintf(msgbuf, sizeof msgbuf - 1, fmt, ap);
   16.41 +		msgbuf[sizeof msgbuf - 1] = 0;
   16.42 +		MessageBox(0, msgbuf, "Fatal error", MB_OK | MB_ICONSTOP);
   16.43 +	}
   16.44 +#endif
   16.45 +}
   16.46 +
   16.47 +void info_log(const char *fmt, ...)
   16.48 +{
   16.49 +	va_list ap;
   16.50 +
   16.51 +	va_start(ap, fmt);
   16.52 +	logmsg(LOG_INFO, fmt, ap);
   16.53 +	va_end(ap);
   16.54 +}
   16.55 +
   16.56 +void warning_log(const char *fmt, ...)
   16.57 +{
   16.58 +	va_list ap;
   16.59 +
   16.60 +	va_start(ap, fmt);
   16.61 +	logmsg(LOG_WARNING, fmt, ap);
   16.62 +	va_end(ap);
   16.63 +}
   16.64 +
   16.65 +void error_log(const char *fmt, ...)
   16.66 +{
   16.67 +	va_list ap;
   16.68 +
   16.69 +	va_start(ap, fmt);
   16.70 +	logmsg(LOG_ERROR, fmt, ap);
   16.71 +	va_end(ap);
   16.72 +}
   16.73 +
   16.74 +void fatal_log(const char *fmt, ...)
   16.75 +{
   16.76 +	va_list ap;
   16.77 +
   16.78 +	va_start(ap, fmt);
   16.79 +	logmsg(LOG_FATAL, fmt, ap);
   16.80 +	va_end(ap);
   16.81 +}
   16.82 +
   16.83 +void debug_log(const char *fmt, ...)
   16.84 +{
   16.85 +	va_list ap;
   16.86 +
   16.87 +	va_start(ap, fmt);
   16.88 +	logmsg(LOG_DEBUG, fmt, ap);
   16.89 +	va_end(ap);
   16.90 +}
   16.91 +
   16.92 +enum {
   16.93 +	BLACK = 0,
   16.94 +	RED,
   16.95 +	GREEN,
   16.96 +	YELLOW,
   16.97 +	BLUE,
   16.98 +	MAGENTA,
   16.99 +	CYAN,
  16.100 +	WHITE
  16.101 +};
  16.102 +
  16.103 +#define ANSI_FGCOLOR(x)	(30 + (x))
  16.104 +#define ANSI_BGCOLOR(x)	(40 + (x))
  16.105 +
  16.106 +static int typecolor(int type)
  16.107 +{
  16.108 +	switch(type) {
  16.109 +	case LOG_ERROR:
  16.110 +		return ANSI_FGCOLOR(RED);
  16.111 +	case LOG_FATAL:
  16.112 +		return ANSI_FGCOLOR(RED);	// TODO differentiate from LOG_ERROR
  16.113 +	case LOG_WARNING:
  16.114 +		return ANSI_FGCOLOR(YELLOW);
  16.115 +	case LOG_DEBUG:
  16.116 +		return ANSI_FGCOLOR(MAGENTA);
  16.117 +	default:
  16.118 +		break;
  16.119 +	}
  16.120 +	return 37;
  16.121 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/logger.h	Sun Aug 24 09:41:24 2014 +0300
    17.3 @@ -0,0 +1,10 @@
    17.4 +#ifndef LOGGER_H_
    17.5 +#define LOGGER_H_
    17.6 +
    17.7 +void info_log(const char *fmt, ...);
    17.8 +void warning_log(const char *fmt, ...);
    17.9 +void error_log(const char *fmt, ...);
   17.10 +void fatal_log(const char *fmt, ...);
   17.11 +void debug_log(const char *fmt, ...);
   17.12 +
   17.13 +#endif	// LOGGER_H_
    18.1 --- a/src/main.cc	Sat Aug 23 12:03:29 2014 +0300
    18.2 +++ b/src/main.cc	Sun Aug 24 09:41:24 2014 +0300
    18.3 @@ -2,6 +2,7 @@
    18.4  #include <stdlib.h>
    18.5  #include "opengl.h"
    18.6  #include "game.h"
    18.7 +#include "gameopt.h"
    18.8  #include "vr/vr.h"
    18.9  
   18.10  static bool init();
   18.11 @@ -23,8 +24,13 @@
   18.12  {
   18.13  	glutInitWindowSize(1024, 600);
   18.14  	glutInit(&argc, argv);
   18.15 -	glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
   18.16 -	glutCreateWindow("VR Chess");
   18.17 +
   18.18 +	if(!parse_args(argc, argv)) {
   18.19 +		return 1;
   18.20 +	}
   18.21 +
   18.22 +	glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | (opt.stereo ? GLUT_STEREO : 0));
   18.23 +	glutCreateWindow("LD48 #30 - connected worlds");
   18.24  
   18.25  	glutDisplayFunc(display);
   18.26  	glutIdleFunc(idle);
   18.27 @@ -53,10 +59,12 @@
   18.28  		return false;
   18.29  	}
   18.30  
   18.31 -	int win_xsz = vr_get_opti(VR_OPT_DISPLAY_WIDTH);
   18.32 -	int win_ysz = vr_get_opti(VR_OPT_DISPLAY_HEIGHT);
   18.33 -	if(win_xsz && win_ysz) {
   18.34 -		glutReshapeWindow(win_xsz, win_ysz);
   18.35 +	if(opt.vr) {
   18.36 +		int win_xsz = vr_get_opti(VR_OPT_DISPLAY_WIDTH);
   18.37 +		int win_ysz = vr_get_opti(VR_OPT_DISPLAY_HEIGHT);
   18.38 +		if(win_xsz && win_ysz) {
   18.39 +			glutReshapeWindow(win_xsz, win_ysz);
   18.40 +		}
   18.41  	}
   18.42  	return true;
   18.43  }
   18.44 @@ -110,8 +118,8 @@
   18.45  			if(xoffs || yoffs) {
   18.46  				printf("repositioning: %d,%d\n", xoffs, yoffs);
   18.47  				glutPositionWindow(xoffs, yoffs);
   18.48 -				fullscreen_pending = true;
   18.49  			}
   18.50 +			fullscreen_pending = true;
   18.51  		} else {
   18.52  			fullscreen_pending = false;
   18.53  			glutPositionWindow(prev_xpos, prev_ypos);
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/material.cc	Sun Aug 24 09:41:24 2014 +0300
    19.3 @@ -0,0 +1,75 @@
    19.4 +#include "opengl.h"
    19.5 +#include "material.h"
    19.6 +#include "unistate.h"
    19.7 +
    19.8 +Material::Material()
    19.9 +	: diffuse(1, 1, 1), specular(0, 0, 0)
   19.10 +{
   19.11 +	alpha = 1.0;
   19.12 +	shininess = 1.0;
   19.13 +
   19.14 +	for(int i=0; i<MAX_MTL_TEXTURES; i++) {
   19.15 +		tex[i] = 0;
   19.16 +	}
   19.17 +}
   19.18 +
   19.19 +
   19.20 +void Material::setup(bool use_textures) const
   19.21 +{
   19.22 +	static bool done_init;
   19.23 +	static int st_diffuse_idx, st_specular_idx, st_shininess_idx, st_alpha_idx;
   19.24 +	static int st_tex_diffuse_idx, st_tex_specular_idx, st_tex_normal_idx;
   19.25 +	static int st_tex_idx[MAX_MTL_TEXTURES];
   19.26 +
   19.27 +	if(!done_init) {
   19.28 +		st_diffuse_idx = add_unistate("st_mtl_diffuse", ST_FLOAT3);
   19.29 +		st_specular_idx = add_unistate("st_mtl_specular", ST_FLOAT3);
   19.30 +		st_shininess_idx = add_unistate("st_mtl_shininess", ST_FLOAT);
   19.31 +		st_alpha_idx = add_unistate("st_mtl_alpha", ST_FLOAT);
   19.32 +		st_tex_diffuse_idx = add_unistate("st_tex_diffuse", ST_INT);
   19.33 +		st_tex_specular_idx = add_unistate("st_tex_specular", ST_INT);
   19.34 +		st_tex_normal_idx = add_unistate("st_tex_normal", ST_INT);
   19.35 +
   19.36 +		for(int i=0; i<MAX_MTL_TEXTURES; i++) {
   19.37 +			char name[32];
   19.38 +			sprintf(name, "st_tex%d", i);
   19.39 +			st_tex_idx[i] = add_unistate(name, ST_INT);
   19.40 +		}
   19.41 +		done_init = true;
   19.42 +	}
   19.43 +
   19.44 +	set_unistate(st_diffuse_idx, diffuse);
   19.45 +	set_unistate(st_specular_idx, specular);
   19.46 +	set_unistate(st_shininess_idx, shininess);
   19.47 +	set_unistate(st_alpha_idx, alpha);
   19.48 +
   19.49 +	if(!use_textures) {
   19.50 +		return;	// we're done
   19.51 +	}
   19.52 +
   19.53 +	const int tex_named_idx[] = {
   19.54 +		st_tex_diffuse_idx, st_tex_specular_idx, st_tex_normal_idx, -1
   19.55 +	};
   19.56 +
   19.57 +	int tex_unit = 0;
   19.58 +	for(int i=0; i<MAX_MTL_TEXTURES; i++) {
   19.59 +		if(tex[i]) {
   19.60 +			bind_texture(tex[i], tex_unit);
   19.61 +
   19.62 +			if(tex_named_idx[i] != -1) {
   19.63 +				set_unistate(tex_named_idx[i], tex_unit);
   19.64 +			}
   19.65 +			set_unistate(st_tex_idx[i], tex_unit);
   19.66 +			tex_unit++;
   19.67 +		}
   19.68 +	}
   19.69 +
   19.70 +	// also do fixed-function setup
   19.71 +	float dcol[] = {diffuse.x, diffuse.y, diffuse.z, alpha};
   19.72 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, dcol);
   19.73 +
   19.74 +	float scol[] = {specular.x, specular.y, specular.z, 1.0f};
   19.75 +	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scol);
   19.76 +
   19.77 +	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
   19.78 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/material.h	Sun Aug 24 09:41:24 2014 +0300
    20.3 @@ -0,0 +1,29 @@
    20.4 +#ifndef MATERIAL_H_
    20.5 +#define MATERIAL_H_
    20.6 +
    20.7 +#include "vmath/vmath.h"
    20.8 +#include "texture.h"
    20.9 +
   20.10 +enum {
   20.11 +	TEX_DIFFUSE,
   20.12 +	TEX_SPECULAR,
   20.13 +	TEX_NORMAL,
   20.14 +	TEX_MISC,
   20.15 +
   20.16 +	MAX_MTL_TEXTURES
   20.17 +};
   20.18 +
   20.19 +class Material {
   20.20 +public:
   20.21 +	Vector3 diffuse, specular;
   20.22 +	float alpha;
   20.23 +	float shininess;
   20.24 +
   20.25 +	Texture *tex[MAX_MTL_TEXTURES];
   20.26 +
   20.27 +	Material();
   20.28 +
   20.29 +	void setup(bool use_textures = true) const;
   20.30 +};
   20.31 +
   20.32 +#endif	// MATERIAL_H_
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/src/mesh.cc	Sun Aug 24 09:41:24 2014 +0300
    21.3 @@ -0,0 +1,1024 @@
    21.4 +#include <stdio.h>
    21.5 +#include <stdlib.h>
    21.6 +#include <float.h>
    21.7 +#include <assert.h>
    21.8 +#include "opengl.h"
    21.9 +#include "mesh.h"
   21.10 +#include "xform_node.h"
   21.11 +#include "shader.h"
   21.12 +#include "logger.h"
   21.13 +
   21.14 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5 };
   21.15 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
   21.16 +float Mesh::vertex_sel_dist = 0.01;
   21.17 +float Mesh::vis_vecsize = 1.0;
   21.18 +
   21.19 +Mesh::Mesh()
   21.20 +{
   21.21 +	clear();
   21.22 +
   21.23 +	glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   21.24 +
   21.25 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   21.26 +		vattr[i].vbo = buffer_objects[i];
   21.27 +	}
   21.28 +	ibo = buffer_objects[NUM_MESH_ATTR];
   21.29 +	wire_ibo = 0;
   21.30 +}
   21.31 +
   21.32 +Mesh::~Mesh()
   21.33 +{
   21.34 +	glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   21.35 +
   21.36 +	if(wire_ibo) {
   21.37 +		glDeleteBuffers(1, &wire_ibo);
   21.38 +	}
   21.39 +}
   21.40 +
   21.41 +void Mesh::set_name(const char *name)
   21.42 +{
   21.43 +	this->name = name;
   21.44 +}
   21.45 +
   21.46 +const char *Mesh::get_name() const
   21.47 +{
   21.48 +	return name.c_str();
   21.49 +}
   21.50 +
   21.51 +bool Mesh::has_attrib(int attr) const
   21.52 +{
   21.53 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
   21.54 +		return false;
   21.55 +	}
   21.56 +
   21.57 +	// if neither of these is valid, then nobody has set this attribute
   21.58 +	return vattr[attr].vbo_valid || vattr[attr].data_valid;
   21.59 +}
   21.60 +
   21.61 +void Mesh::clear()
   21.62 +{
   21.63 +	bones.clear();
   21.64 +
   21.65 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   21.66 +		vattr[i].nelem = 0;
   21.67 +		vattr[i].vbo_valid = false;
   21.68 +		vattr[i].data_valid = false;
   21.69 +		//vattr[i].sdr_loc = -1;
   21.70 +		vattr[i].data.clear();
   21.71 +	}
   21.72 +	ibo_valid = idata_valid = false;
   21.73 +	idata.clear();
   21.74 +
   21.75 +	wire_ibo_valid = false;
   21.76 +
   21.77 +	nverts = nfaces = 0;
   21.78 +
   21.79 +	bsph_valid = false;
   21.80 +	aabb_valid = false;
   21.81 +}
   21.82 +
   21.83 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
   21.84 +{
   21.85 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
   21.86 +		error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
   21.87 +		return 0;
   21.88 +	}
   21.89 +
   21.90 +	if(nverts && num != nverts) {
   21.91 +		error_log("%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
   21.92 +		return 0;
   21.93 +	}
   21.94 +	nverts = num;
   21.95 +
   21.96 +	vattr[attrib].data.clear();
   21.97 +	vattr[attrib].nelem = nelem;
   21.98 +	vattr[attrib].data.resize(num * nelem);
   21.99 +
  21.100 +	if(data) {
  21.101 +		memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
  21.102 +	}
  21.103 +
  21.104 +	vattr[attrib].data_valid = true;
  21.105 +	vattr[attrib].vbo_valid = false;
  21.106 +	return &vattr[attrib].data[0];
  21.107 +}
  21.108 +
  21.109 +float *Mesh::get_attrib_data(int attrib)
  21.110 +{
  21.111 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  21.112 +		error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  21.113 +		return 0;
  21.114 +	}
  21.115 +
  21.116 +	vattr[attrib].vbo_valid = false;
  21.117 +	return (float*)((const Mesh*)this)->get_attrib_data(attrib);
  21.118 +}
  21.119 +
  21.120 +const float *Mesh::get_attrib_data(int attrib) const
  21.121 +{
  21.122 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  21.123 +		error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  21.124 +		return 0;
  21.125 +	}
  21.126 +
  21.127 +	if(!vattr[attrib].data_valid) {
  21.128 +#if GL_ES_VERSION_2_0
  21.129 +		error_log("%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
  21.130 +		return 0;
  21.131 +#else
  21.132 +		if(!vattr[attrib].vbo_valid) {
  21.133 +			error_log("%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
  21.134 +			return 0;
  21.135 +		}
  21.136 +
  21.137 +		// local data copy is unavailable, grab the data from the vbo
  21.138 +		Mesh *m = (Mesh*)this;
  21.139 +		m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
  21.140 +
  21.141 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
  21.142 +		void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
  21.143 +		memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
  21.144 +		glUnmapBuffer(GL_ARRAY_BUFFER);
  21.145 +
  21.146 +		vattr[attrib].data_valid = true;
  21.147 +#endif
  21.148 +	}
  21.149 +
  21.150 +	return &vattr[attrib].data[0];
  21.151 +}
  21.152 +
  21.153 +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
  21.154 +{
  21.155 +	float *data = get_attrib_data(attrib);
  21.156 +	if(data) {
  21.157 +		data += idx * vattr[attrib].nelem;
  21.158 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  21.159 +			data[i] = v[i];
  21.160 +		}
  21.161 +	}
  21.162 +}
  21.163 +
  21.164 +Vector4 Mesh::get_attrib(int attrib, int idx) const
  21.165 +{
  21.166 +	Vector4 v(0.0, 0.0, 0.0, 1.0);
  21.167 +	const float *data = get_attrib_data(attrib);
  21.168 +	if(data) {
  21.169 +		data += idx * vattr[attrib].nelem;
  21.170 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  21.171 +			v[i] = data[i];
  21.172 +		}
  21.173 +	}
  21.174 +	return v;
  21.175 +}
  21.176 +
  21.177 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
  21.178 +{
  21.179 +	int nidx = nfaces * 3;
  21.180 +	if(nidx && num != nidx) {
  21.181 +		error_log("%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
  21.182 +		return 0;
  21.183 +	}
  21.184 +	nfaces = num / 3;
  21.185 +
  21.186 +	idata.clear();
  21.187 +	idata.resize(num);
  21.188 +
  21.189 +	if(indices) {
  21.190 +		memcpy(&idata[0], indices, num * sizeof *indices);
  21.191 +	}
  21.192 +
  21.193 +	idata_valid = true;
  21.194 +	ibo_valid = false;
  21.195 +
  21.196 +	return &idata[0];
  21.197 +}
  21.198 +
  21.199 +unsigned int *Mesh::get_index_data()
  21.200 +{
  21.201 +	ibo_valid = false;
  21.202 +	return (unsigned int*)((const Mesh*)this)->get_index_data();
  21.203 +}
  21.204 +
  21.205 +const unsigned int *Mesh::get_index_data() const
  21.206 +{
  21.207 +	if(!idata_valid) {
  21.208 +#if GL_ES_VERSION_2_0
  21.209 +		error_log("%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
  21.210 +		return 0;
  21.211 +#else
  21.212 +		if(!ibo_valid) {
  21.213 +			error_log("%s: indices unavailable\n", __FUNCTION__);
  21.214 +			return 0;
  21.215 +		}
  21.216 +
  21.217 +		// local data copy is unavailable, gram the data from the ibo
  21.218 +		Mesh *m = (Mesh*)this;
  21.219 +		int nidx = nfaces * 3;
  21.220 +		m->idata.resize(nidx);
  21.221 +
  21.222 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  21.223 +		void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
  21.224 +		memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
  21.225 +		glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
  21.226 +
  21.227 +		idata_valid = true;
  21.228 +#endif
  21.229 +	}
  21.230 +
  21.231 +	return &idata[0];
  21.232 +}
  21.233 +
  21.234 +void Mesh::append(const Mesh &mesh)
  21.235 +{
  21.236 +	unsigned int idxoffs = nverts;
  21.237 +
  21.238 +	nverts += mesh.nverts;
  21.239 +	nfaces += mesh.nfaces;
  21.240 +
  21.241 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.242 +		if(has_attrib(i) && mesh.has_attrib(i)) {
  21.243 +			// force validating the data arrays
  21.244 +			get_attrib_data(i);
  21.245 +			mesh.get_attrib_data(i);
  21.246 +
  21.247 +			// append the mesh data
  21.248 +			vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
  21.249 +		}
  21.250 +	}
  21.251 +
  21.252 +	if(ibo_valid || idata_valid) {
  21.253 +		// make index arrays valid
  21.254 +		get_index_data();
  21.255 +		mesh.get_index_data();
  21.256 +
  21.257 +		size_t orig_sz = idata.size();
  21.258 +
  21.259 +		idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
  21.260 +
  21.261 +		// fixup all the new indices
  21.262 +		for(size_t i=orig_sz; i<idata.size(); i++) {
  21.263 +			idata[i] += idxoffs;
  21.264 +		}
  21.265 +	}
  21.266 +
  21.267 +	// fuck everything
  21.268 +	wire_ibo_valid = false;
  21.269 +	aabb_valid = false;
  21.270 +	bsph_valid = false;
  21.271 +}
  21.272 +
  21.273 +// assemble a complete vertex by adding all the useful attributes
  21.274 +void Mesh::vertex(float x, float y, float z)
  21.275 +{
  21.276 +	cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
  21.277 +	vattr[MESH_ATTR_VERTEX].data_valid = true;
  21.278 +	vattr[MESH_ATTR_VERTEX].nelem = 3;
  21.279 +
  21.280 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.281 +		if(vattr[i].data_valid) {
  21.282 +			for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
  21.283 +				vattr[i].data.push_back(cur_val[i][j]);
  21.284 +			}
  21.285 +		}
  21.286 +		vattr[i].vbo_valid = false;
  21.287 +	}
  21.288 +
  21.289 +	if(idata_valid) {
  21.290 +		idata.clear();
  21.291 +	}
  21.292 +	ibo_valid = idata_valid = false;
  21.293 +}
  21.294 +
  21.295 +void Mesh::normal(float nx, float ny, float nz)
  21.296 +{
  21.297 +	cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
  21.298 +	vattr[MESH_ATTR_NORMAL].data_valid = true;
  21.299 +	vattr[MESH_ATTR_NORMAL].nelem = 3;
  21.300 +}
  21.301 +
  21.302 +void Mesh::tangent(float tx, float ty, float tz)
  21.303 +{
  21.304 +	cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
  21.305 +	vattr[MESH_ATTR_TANGENT].data_valid = true;
  21.306 +	vattr[MESH_ATTR_TANGENT].nelem = 3;
  21.307 +}
  21.308 +
  21.309 +void Mesh::texcoord(float u, float v, float w)
  21.310 +{
  21.311 +	cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
  21.312 +	vattr[MESH_ATTR_TEXCOORD].data_valid = true;
  21.313 +	vattr[MESH_ATTR_TEXCOORD].nelem = 3;
  21.314 +}
  21.315 +
  21.316 +void Mesh::boneweights(float w1, float w2, float w3, float w4)
  21.317 +{
  21.318 +	cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
  21.319 +	vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
  21.320 +	vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
  21.321 +}
  21.322 +
  21.323 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
  21.324 +{
  21.325 +	cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
  21.326 +	vattr[MESH_ATTR_BONEIDX].data_valid = true;
  21.327 +	vattr[MESH_ATTR_BONEIDX].nelem = 4;
  21.328 +}
  21.329 +
  21.330 +/// static function
  21.331 +void Mesh::set_attrib_location(int attr, int loc)
  21.332 +{
  21.333 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  21.334 +		return;
  21.335 +	}
  21.336 +	Mesh::global_sdr_loc[attr] = loc;
  21.337 +}
  21.338 +
  21.339 +/// static function
  21.340 +int Mesh::get_attrib_location(int attr)
  21.341 +{
  21.342 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  21.343 +		return -1;
  21.344 +	}
  21.345 +	return Mesh::global_sdr_loc[attr];
  21.346 +}
  21.347 +
  21.348 +/// static function
  21.349 +void Mesh::clear_attrib_locations()
  21.350 +{
  21.351 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.352 +		Mesh::global_sdr_loc[i] = -1;
  21.353 +	}
  21.354 +}
  21.355 +
  21.356 +/// static function
  21.357 +void Mesh::set_vis_vecsize(float sz)
  21.358 +{
  21.359 +	Mesh::vis_vecsize = sz;
  21.360 +}
  21.361 +
  21.362 +float Mesh::get_vis_vecsize()
  21.363 +{
  21.364 +	return Mesh::vis_vecsize;
  21.365 +}
  21.366 +
  21.367 +void Mesh::apply_xform(const Matrix4x4 &xform)
  21.368 +{
  21.369 +	Matrix4x4 dir_xform = xform;
  21.370 +	dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
  21.371 +	dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
  21.372 +	dir_xform[3][3] = 1.0f;
  21.373 +
  21.374 +	apply_xform(xform, dir_xform);
  21.375 +}
  21.376 +
  21.377 +void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
  21.378 +{
  21.379 +	for(unsigned int i=0; i<nverts; i++) {
  21.380 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
  21.381 +		set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
  21.382 +
  21.383 +		if(has_attrib(MESH_ATTR_NORMAL)) {
  21.384 +			Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
  21.385 +			set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
  21.386 +		}
  21.387 +		if(has_attrib(MESH_ATTR_TANGENT)) {
  21.388 +			Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
  21.389 +			set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
  21.390 +		}
  21.391 +	}
  21.392 +}
  21.393 +
  21.394 +int Mesh::add_bone(XFormNode *bone)
  21.395 +{
  21.396 +	int idx = bones.size();
  21.397 +	bones.push_back(bone);
  21.398 +	return idx;
  21.399 +}
  21.400 +
  21.401 +const XFormNode *Mesh::get_bone(int idx) const
  21.402 +{
  21.403 +	if(idx < 0 || idx >= (int)bones.size()) {
  21.404 +		return 0;
  21.405 +	}
  21.406 +	return bones[idx];
  21.407 +}
  21.408 +
  21.409 +int Mesh::get_bones_count() const
  21.410 +{
  21.411 +	return (int)bones.size();
  21.412 +}
  21.413 +
  21.414 +void Mesh::draw() const
  21.415 +{
  21.416 +	const ShaderProg *cur_sdr = get_current_shader();
  21.417 +#ifdef GL_ES_VERSION_2_0
  21.418 +	if(!cur_sdr) {
  21.419 +		error_log("%s: CrippledGL ES can't draw without a shader\n", __FUNCTION__);
  21.420 +		return;
  21.421 +	}
  21.422 +#endif
  21.423 +
  21.424 +	((Mesh*)this)->update_buffers();
  21.425 +
  21.426 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
  21.427 +		error_log("%s: invalid vertex buffer\n", __FUNCTION__);
  21.428 +		return;
  21.429 +	}
  21.430 +
  21.431 +	if(cur_sdr) {
  21.432 +		// rendering with shaders
  21.433 +		if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  21.434 +			error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
  21.435 +			return;
  21.436 +		}
  21.437 +
  21.438 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.439 +			int loc = global_sdr_loc[i];
  21.440 +			if(loc >= 0 && vattr[i].vbo_valid) {
  21.441 +				glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  21.442 +				glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  21.443 +				glEnableVertexAttribArray(loc);
  21.444 +			}
  21.445 +		}
  21.446 +	} else {
  21.447 +#ifndef GL_ES_VERSION_2_0
  21.448 +		// rendering with fixed-function (not available in GLES2)
  21.449 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
  21.450 +		glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
  21.451 +		glEnableClientState(GL_VERTEX_ARRAY);
  21.452 +
  21.453 +		if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
  21.454 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
  21.455 +			glNormalPointer(GL_FLOAT, 0, 0);
  21.456 +			glEnableClientState(GL_NORMAL_ARRAY);
  21.457 +		}
  21.458 +		if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
  21.459 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
  21.460 +			glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
  21.461 +			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  21.462 +		}
  21.463 +		if(vattr[MESH_ATTR_COLOR].vbo_valid) {
  21.464 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
  21.465 +			glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
  21.466 +			glEnableClientState(GL_COLOR_ARRAY);
  21.467 +		}
  21.468 +#endif
  21.469 +	}
  21.470 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  21.471 +
  21.472 +	if(ibo_valid) {
  21.473 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  21.474 +		glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
  21.475 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  21.476 +	} else {
  21.477 +		glDrawArrays(GL_TRIANGLES, 0, nverts);
  21.478 +	}
  21.479 +
  21.480 +	if(cur_sdr) {
  21.481 +		// rendered with shaders
  21.482 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.483 +			int loc = global_sdr_loc[i];
  21.484 +			if(loc >= 0 && vattr[i].vbo_valid) {
  21.485 +				glDisableVertexAttribArray(loc);
  21.486 +			}
  21.487 +		}
  21.488 +	} else {
  21.489 +#ifndef GL_ES_VERSION_2_0
  21.490 +		// rendered with fixed-function
  21.491 +		glDisableClientState(GL_VERTEX_ARRAY);
  21.492 +		if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
  21.493 +			glDisableClientState(GL_NORMAL_ARRAY);
  21.494 +		}
  21.495 +		if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
  21.496 +			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  21.497 +		}
  21.498 +		if(vattr[MESH_ATTR_COLOR].vbo_valid) {
  21.499 +			glDisableClientState(GL_COLOR_ARRAY);
  21.500 +		}
  21.501 +#endif
  21.502 +	}
  21.503 +}
  21.504 +
  21.505 +void Mesh::draw_wire() const
  21.506 +{
  21.507 +	((Mesh*)this)->update_wire_ibo();
  21.508 +
  21.509 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
  21.510 +		error_log("%s: invalid vertex buffer\n", __FUNCTION__);
  21.511 +		return;
  21.512 +	}
  21.513 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  21.514 +		error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
  21.515 +		return;
  21.516 +	}
  21.517 +
  21.518 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.519 +		int loc = global_sdr_loc[i];
  21.520 +		if(loc >= 0 && vattr[i].vbo_valid) {
  21.521 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  21.522 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  21.523 +			glEnableVertexAttribArray(loc);
  21.524 +		}
  21.525 +	}
  21.526 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  21.527 +
  21.528 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
  21.529 +	glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
  21.530 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  21.531 +
  21.532 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.533 +		int loc = global_sdr_loc[i];
  21.534 +		if(loc >= 0 && vattr[i].vbo_valid) {
  21.535 +			glDisableVertexAttribArray(loc);
  21.536 +		}
  21.537 +	}
  21.538 +}
  21.539 +
  21.540 +void Mesh::draw_vertices() const
  21.541 +{
  21.542 +	((Mesh*)this)->update_buffers();
  21.543 +
  21.544 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
  21.545 +		error_log("%s: invalid vertex buffer\n", __FUNCTION__);
  21.546 +		return;
  21.547 +	}
  21.548 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  21.549 +		error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
  21.550 +		return;
  21.551 +	}
  21.552 +
  21.553 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.554 +		int loc = global_sdr_loc[i];
  21.555 +		if(loc >= 0 && vattr[i].vbo_valid) {
  21.556 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  21.557 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  21.558 +			glEnableVertexAttribArray(loc);
  21.559 +		}
  21.560 +	}
  21.561 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  21.562 +
  21.563 +	glDrawArrays(GL_POINTS, 0, nverts);
  21.564 +
  21.565 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.566 +		int loc = global_sdr_loc[i];
  21.567 +		if(loc >= 0 && vattr[i].vbo_valid) {
  21.568 +			glDisableVertexAttribArray(loc);
  21.569 +		}
  21.570 +	}
  21.571 +}
  21.572 +
  21.573 +void Mesh::draw_normals() const
  21.574 +{
  21.575 +#ifdef USE_OLDGL
  21.576 +	int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  21.577 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  21.578 +	Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  21.579 +
  21.580 +	if(!varr || !norm || vert_loc < 0) {
  21.581 +		return;
  21.582 +	}
  21.583 +
  21.584 +	glBegin(GL_LINES);
  21.585 +	for(size_t i=0; i<nverts; i++) {
  21.586 +		glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  21.587 +		Vector3 end = varr[i] + norm[i] * vis_vecsize;
  21.588 +		glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  21.589 +	}
  21.590 +	glEnd();
  21.591 +
  21.592 +#endif	// USE_OLDGL
  21.593 +}
  21.594 +
  21.595 +void Mesh::draw_tangents() const
  21.596 +{
  21.597 +#ifdef USE_OLDGL
  21.598 +	int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  21.599 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  21.600 +	Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
  21.601 +
  21.602 +	if(!varr || !tang || vert_loc < 0) {
  21.603 +		return;
  21.604 +	}
  21.605 +
  21.606 +	glBegin(GL_LINES);
  21.607 +	for(size_t i=0; i<nverts; i++) {
  21.608 +		glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  21.609 +		Vector3 end = varr[i] + tang[i] * vis_vecsize;
  21.610 +		glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  21.611 +	}
  21.612 +	glEnd();
  21.613 +
  21.614 +#endif	// USE_OLDGL
  21.615 +}
  21.616 +
  21.617 +void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
  21.618 +{
  21.619 +	if(!aabb_valid) {
  21.620 +		((Mesh*)this)->calc_aabb();
  21.621 +	}
  21.622 +	*vmin = aabb.min;
  21.623 +	*vmax = aabb.max;
  21.624 +}
  21.625 +
  21.626 +const AABox &Mesh::get_aabbox() const
  21.627 +{
  21.628 +	if(!aabb_valid) {
  21.629 +		((Mesh*)this)->calc_aabb();
  21.630 +	}
  21.631 +	return aabb;
  21.632 +}
  21.633 +
  21.634 +float Mesh::get_bsphere(Vector3 *center, float *rad) const
  21.635 +{
  21.636 +	if(!bsph_valid) {
  21.637 +		((Mesh*)this)->calc_bsph();
  21.638 +	}
  21.639 +	*center = bsph.center;
  21.640 +	*rad = bsph.radius;
  21.641 +	return bsph.radius;
  21.642 +}
  21.643 +
  21.644 +const Sphere &Mesh::get_bsphere() const
  21.645 +{
  21.646 +	if(!bsph_valid) {
  21.647 +		((Mesh*)this)->calc_bsph();
  21.648 +	}
  21.649 +	return bsph;
  21.650 +}
  21.651 +
  21.652 +/// static function
  21.653 +void Mesh::set_intersect_mode(unsigned int mode)
  21.654 +{
  21.655 +	Mesh::intersect_mode = mode;
  21.656 +}
  21.657 +
  21.658 +/// static function
  21.659 +unsigned int Mesh::get_intersect_mode()
  21.660 +{
  21.661 +	return Mesh::intersect_mode;
  21.662 +}
  21.663 +
  21.664 +/// static function
  21.665 +void Mesh::set_vertex_select_distance(float dist)
  21.666 +{
  21.667 +	Mesh::vertex_sel_dist = dist;
  21.668 +}
  21.669 +
  21.670 +/// static function
  21.671 +float Mesh::get_vertex_select_distance()
  21.672 +{
  21.673 +	return Mesh::vertex_sel_dist;
  21.674 +}
  21.675 +
  21.676 +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
  21.677 +{
  21.678 +	assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
  21.679 +
  21.680 +	const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  21.681 +	const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  21.682 +	if(!varr) {
  21.683 +		return false;
  21.684 +	}
  21.685 +	const unsigned int *idxarr = get_index_data();
  21.686 +
  21.687 +	// first test with the bounding box
  21.688 +	AABox box;
  21.689 +	get_aabbox(&box.min, &box.max);
  21.690 +	if(!box.intersect(ray)) {
  21.691 +		return false;
  21.692 +	}
  21.693 +
  21.694 +	HitPoint nearest_hit;
  21.695 +	nearest_hit.dist = FLT_MAX;
  21.696 +	nearest_hit.obj = 0;
  21.697 +
  21.698 +	if(Mesh::intersect_mode & ISECT_VERTICES) {
  21.699 +		// we asked for "intersections" with the vertices of the mesh
  21.700 +		long nearest_vidx = -1;
  21.701 +		float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
  21.702 +
  21.703 +		for(unsigned int i=0; i<nverts; i++) {
  21.704 +
  21.705 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
  21.706 +				continue;
  21.707 +			}
  21.708 +
  21.709 +			// project the vertex onto the ray line
  21.710 +			float t = dot_product(varr[i] - ray.origin, ray.dir);
  21.711 +			Vector3 vproj = ray.origin + ray.dir * t;
  21.712 +
  21.713 +			float dist_sq = (vproj - varr[i]).length_sq();
  21.714 +			if(dist_sq < thres_sq) {
  21.715 +				if(!hit) {
  21.716 +					return true;
  21.717 +				}
  21.718 +				if(t < nearest_hit.dist) {
  21.719 +					nearest_hit.dist = t;
  21.720 +					nearest_vidx = i;
  21.721 +				}
  21.722 +			}
  21.723 +		}
  21.724 +
  21.725 +		if(nearest_vidx != -1) {
  21.726 +			hitvert = varr[nearest_vidx];
  21.727 +			nearest_hit.obj = &hitvert;
  21.728 +		}
  21.729 +
  21.730 +	} else {
  21.731 +		// regular intersection test with polygons
  21.732 +
  21.733 +		for(unsigned int i=0; i<nfaces; i++) {
  21.734 +			Triangle face(i, varr, idxarr);
  21.735 +
  21.736 +			// ignore back-facing polygons if the mode flags include ISECT_FRONT
  21.737 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
  21.738 +				continue;
  21.739 +			}
  21.740 +
  21.741 +			HitPoint fhit;
  21.742 +			if(face.intersect(ray, hit ? &fhit : 0)) {
  21.743 +				if(!hit) {
  21.744 +					return true;
  21.745 +				}
  21.746 +				if(fhit.dist < nearest_hit.dist) {
  21.747 +					nearest_hit = fhit;
  21.748 +					hitface = face;
  21.749 +				}
  21.750 +			}
  21.751 +		}
  21.752 +	}
  21.753 +
  21.754 +	if(nearest_hit.obj) {
  21.755 +		if(hit) {
  21.756 +			*hit = nearest_hit;
  21.757 +
  21.758 +			// if we are interested in the mesh and not the faces set obj to this
  21.759 +			if(Mesh::intersect_mode & ISECT_FACE) {
  21.760 +				hit->obj = &hitface;
  21.761 +			} else if(Mesh::intersect_mode & ISECT_VERTICES) {
  21.762 +				hit->obj = &hitvert;
  21.763 +			} else {
  21.764 +				hit->obj = this;
  21.765 +			}
  21.766 +		}
  21.767 +		return true;
  21.768 +	}
  21.769 +	return false;
  21.770 +}
  21.771 +
  21.772 +
  21.773 +// ------ private member functions ------
  21.774 +
  21.775 +void Mesh::calc_aabb()
  21.776 +{
  21.777 +	// the cast is to force calling the const version which doesn't invalidate
  21.778 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
  21.779 +		return;
  21.780 +	}
  21.781 +
  21.782 +	aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
  21.783 +	aabb.max = -aabb.min;
  21.784 +
  21.785 +	for(unsigned int i=0; i<nverts; i++) {
  21.786 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
  21.787 +		for(int j=0; j<3; j++) {
  21.788 +			if(v[j] < aabb.min[j]) {
  21.789 +				aabb.min[j] = v[j];
  21.790 +			}
  21.791 +			if(v[j] > aabb.max[j]) {
  21.792 +				aabb.max[j] = v[j];
  21.793 +			}
  21.794 +		}
  21.795 +	}
  21.796 +	aabb_valid = true;
  21.797 +}
  21.798 +
  21.799 +void Mesh::calc_bsph()
  21.800 +{
  21.801 +	// the cast is to force calling the const version which doesn't invalidate
  21.802 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
  21.803 +		return;
  21.804 +	}
  21.805 +
  21.806 +	Vector3 v;
  21.807 +	bsph.center = Vector3(0, 0, 0);
  21.808 +
  21.809 +	// first find the center
  21.810 +	for(unsigned int i=0; i<nverts; i++) {
  21.811 +		v = get_attrib(MESH_ATTR_VERTEX, i);
  21.812 +		bsph.center += v;
  21.813 +	}
  21.814 +	bsph.center /= (float)nverts;
  21.815 +
  21.816 +	bsph.radius = 0.0f;
  21.817 +	for(unsigned int i=0; i<nverts; i++) {
  21.818 +		v = get_attrib(MESH_ATTR_VERTEX, i);
  21.819 +		float dist_sq = (v - bsph.center).length_sq();
  21.820 +		if(dist_sq > bsph.radius) {
  21.821 +			bsph.radius = dist_sq;
  21.822 +		}
  21.823 +	}
  21.824 +	bsph.radius = sqrt(bsph.radius);
  21.825 +
  21.826 +	bsph_valid = true;
  21.827 +}
  21.828 +
  21.829 +void Mesh::update_buffers()
  21.830 +{
  21.831 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  21.832 +		if(has_attrib(i) && !vattr[i].vbo_valid) {
  21.833 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  21.834 +			glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
  21.835 +			vattr[i].vbo_valid = true;
  21.836 +		}
  21.837 +	}
  21.838 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  21.839 +
  21.840 +	if(idata_valid && !ibo_valid) {
  21.841 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  21.842 +		glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
  21.843 +		ibo_valid = true;
  21.844 +	}
  21.845 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  21.846 +}
  21.847 +
  21.848 +void Mesh::update_wire_ibo()
  21.849 +{
  21.850 +	update_buffers();
  21.851 +
  21.852 +	if(wire_ibo_valid) {
  21.853 +		return;
  21.854 +	}
  21.855 +
  21.856 +	if(!wire_ibo) {
  21.857 +		glGenBuffers(1, &wire_ibo);
  21.858 +	}
  21.859 +
  21.860 +	unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
  21.861 +	unsigned int *dest = wire_idxarr;
  21.862 +
  21.863 +	if(ibo_valid) {
  21.864 +		// we're dealing with an indexed mesh
  21.865 +		const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
  21.866 +
  21.867 +		for(unsigned int i=0; i<nfaces; i++) {
  21.868 +			*dest++ = idxarr[0];
  21.869 +			*dest++ = idxarr[1];
  21.870 +			*dest++ = idxarr[1];
  21.871 +			*dest++ = idxarr[2];
  21.872 +			*dest++ = idxarr[2];
  21.873 +			*dest++ = idxarr[0];
  21.874 +			idxarr += 3;
  21.875 +		}
  21.876 +	} else {
  21.877 +		// not an indexed mesh ...
  21.878 +		for(unsigned int i=0; i<nfaces; i++) {
  21.879 +			int vidx = i * 3;
  21.880 +			*dest++ = vidx;
  21.881 +			*dest++ = vidx + 1;
  21.882 +			*dest++ = vidx + 1;
  21.883 +			*dest++ = vidx + 2;
  21.884 +			*dest++ = vidx + 2;
  21.885 +			*dest++ = vidx;
  21.886 +		}
  21.887 +	}
  21.888 +
  21.889 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
  21.890 +	glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
  21.891 +	delete [] wire_idxarr;
  21.892 +	wire_ibo_valid = true;
  21.893 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  21.894 +}
  21.895 +
  21.896 +
  21.897 +// ------ class Triangle ------
  21.898 +Triangle::Triangle()
  21.899 +{
  21.900 +	normal_valid = false;
  21.901 +	id = -1;
  21.902 +}
  21.903 +
  21.904 +Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
  21.905 +{
  21.906 +	v[0] = v0;
  21.907 +	v[1] = v1;
  21.908 +	v[2] = v2;
  21.909 +	normal_valid = false;
  21.910 +	id = -1;
  21.911 +}
  21.912 +
  21.913 +Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
  21.914 +{
  21.915 +	if(idxarr) {
  21.916 +		v[0] = varr[idxarr[n * 3]];
  21.917 +		v[1] = varr[idxarr[n * 3 + 1]];
  21.918 +		v[2] = varr[idxarr[n * 3 + 2]];
  21.919 +	} else {
  21.920 +		v[0] = varr[n * 3];
  21.921 +		v[1] = varr[n * 3 + 1];
  21.922 +		v[2] = varr[n * 3 + 2];
  21.923 +	}
  21.924 +	normal_valid = false;
  21.925 +	id = n;
  21.926 +}
  21.927 +
  21.928 +void Triangle::calc_normal()
  21.929 +{
  21.930 +	normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
  21.931 +	normal_valid = true;
  21.932 +}
  21.933 +
  21.934 +const Vector3 &Triangle::get_normal() const
  21.935 +{
  21.936 +	if(!normal_valid) {
  21.937 +		((Triangle*)this)->calc_normal();
  21.938 +	}
  21.939 +	return normal;
  21.940 +}
  21.941 +
  21.942 +void Triangle::transform(const Matrix4x4 &xform)
  21.943 +{
  21.944 +	v[0].transform(xform);
  21.945 +	v[1].transform(xform);
  21.946 +	v[2].transform(xform);
  21.947 +	normal_valid = false;
  21.948 +}
  21.949 +
  21.950 +void Triangle::draw() const
  21.951 +{
  21.952 +	Vector3 n[3];
  21.953 +	n[0] = get_normal();
  21.954 +	n[1] = get_normal();
  21.955 +	n[2] = get_normal();
  21.956 +
  21.957 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
  21.958 +	int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
  21.959 +
  21.960 +	glEnableVertexAttribArray(vloc);
  21.961 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
  21.962 +	glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
  21.963 +
  21.964 +	glDrawArrays(GL_TRIANGLES, 0, 3);
  21.965 +
  21.966 +	glDisableVertexAttribArray(vloc);
  21.967 +	glDisableVertexAttribArray(nloc);
  21.968 +	CHECKGLERR;
  21.969 +}
  21.970 +
  21.971 +void Triangle::draw_wire() const
  21.972 +{
  21.973 +	static const int idxarr[] = {0, 1, 1, 2, 2, 0};
  21.974 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
  21.975 +
  21.976 +	glEnableVertexAttribArray(vloc);
  21.977 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
  21.978 +
  21.979 +	glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
  21.980 +
  21.981 +	glDisableVertexAttribArray(vloc);
  21.982 +	CHECKGLERR;
  21.983 +}
  21.984 +
  21.985 +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
  21.986 +{
  21.987 +	Vector3 norm = get_normal();
  21.988 +
  21.989 +	float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
  21.990 +	if(area_sq < 1e-5) {
  21.991 +		return Vector3(0, 0, 0);
  21.992 +	}
  21.993 +
  21.994 +	float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
  21.995 +	float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
  21.996 +	float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
  21.997 +
  21.998 +	return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
  21.999 +}
 21.1000 +
 21.1001 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
 21.1002 +{
 21.1003 +	Vector3 normal = get_normal();
 21.1004 +
 21.1005 +	float ndotdir = dot_product(ray.dir, normal);
 21.1006 +	if(fabs(ndotdir) < 1e-4) {
 21.1007 +		return false;
 21.1008 +	}
 21.1009 +
 21.1010 +	Vector3 vertdir = v[0] - ray.origin;
 21.1011 +	float t = dot_product(normal, vertdir) / ndotdir;
 21.1012 +
 21.1013 +	Vector3 pos = ray.origin + ray.dir * t;
 21.1014 +	Vector3 bary = calc_barycentric(pos);
 21.1015 +
 21.1016 +	if(bary.x + bary.y + bary.z > 1.00001) {
 21.1017 +		return false;
 21.1018 +	}
 21.1019 +
 21.1020 +	if(hit) {
 21.1021 +		hit->dist = t;
 21.1022 +		hit->pos = ray.origin + ray.dir * t;
 21.1023 +		hit->normal = normal;
 21.1024 +		hit->obj = this;
 21.1025 +	}
 21.1026 +	return true;
 21.1027 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/mesh.h	Sun Aug 24 09:41:24 2014 +0300
    22.3 @@ -0,0 +1,210 @@
    22.4 +#ifndef MESH_H_
    22.5 +#define MESH_H_
    22.6 +
    22.7 +#include <string>
    22.8 +#include <vector>
    22.9 +#include <vmath/vmath.h>
   22.10 +#include "geom.h"
   22.11 +
   22.12 +enum {
   22.13 +	MESH_ATTR_VERTEX,
   22.14 +	MESH_ATTR_NORMAL,
   22.15 +	MESH_ATTR_TANGENT,
   22.16 +	MESH_ATTR_TEXCOORD,
   22.17 +	MESH_ATTR_COLOR,
   22.18 +	MESH_ATTR_BONEWEIGHTS,
   22.19 +	MESH_ATTR_BONEIDX,
   22.20 +
   22.21 +	NUM_MESH_ATTR
   22.22 +};
   22.23 +
   22.24 +// intersection mode flags
   22.25 +enum {
   22.26 +	ISECT_DEFAULT	= 0,	// default (whole mesh, all intersections)
   22.27 +	ISECT_FRONT		= 1,	// front-faces only
   22.28 +	ISECT_FACE		= 2,	// return intersected face pointer instead of mesh
   22.29 +	ISECT_VERTICES	= 4		// return (?) TODO
   22.30 +};
   22.31 +
   22.32 +class XFormNode;
   22.33 +
   22.34 +
   22.35 +class Triangle {
   22.36 +public:
   22.37 +	Vector3 v[3];
   22.38 +	Vector3 normal;
   22.39 +	bool normal_valid;
   22.40 +	int id;
   22.41 +
   22.42 +	Triangle();
   22.43 +	Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2);
   22.44 +	Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0);
   22.45 +
   22.46 +	/// calculate normal (quite expensive)
   22.47 +	void calc_normal();
   22.48 +	const Vector3 &get_normal() const;
   22.49 +
   22.50 +	void transform(const Matrix4x4 &xform);
   22.51 +
   22.52 +	void draw() const;
   22.53 +	void draw_wire() const;
   22.54 +
   22.55 +	/// calculate barycentric coordinates of a point
   22.56 +	Vector3 calc_barycentric(const Vector3 &pos) const;
   22.57 +
   22.58 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   22.59 +};
   22.60 +
   22.61 +
   22.62 +class Mesh {
   22.63 +private:
   22.64 +	std::string name;
   22.65 +	unsigned int nverts, nfaces;
   22.66 +
   22.67 +	// current value for each attribute for the immedate mode
   22.68 +	// interface.
   22.69 +	Vector4 cur_val[NUM_MESH_ATTR];
   22.70 +
   22.71 +	unsigned int buffer_objects[NUM_MESH_ATTR + 1];
   22.72 +
   22.73 +	// vertex attribute data and buffer objects
   22.74 +	struct {
   22.75 +		int nelem;					// number of elements per attribute range: [1, 4]
   22.76 +		std::vector<float> data;
   22.77 +		unsigned int vbo;
   22.78 +		mutable bool vbo_valid;		// if this is false, the vbo needs updating from the data
   22.79 +		mutable bool data_valid;	// if this is false, the data needs to be pulled from the vbo
   22.80 +		//int sdr_loc;
   22.81 +	} vattr[NUM_MESH_ATTR];
   22.82 +
   22.83 +	static int global_sdr_loc[NUM_MESH_ATTR];
   22.84 +
   22.85 +	std::vector<XFormNode*> bones;	// bones affecting this mesh
   22.86 +
   22.87 +	// index data and buffer object
   22.88 +	std::vector<unsigned int> idata;
   22.89 +	unsigned int ibo;
   22.90 +	mutable bool ibo_valid;
   22.91 +	mutable bool idata_valid;
   22.92 +
   22.93 +	// index buffer object for wireframe rendering (constructed on demand)
   22.94 +	unsigned int wire_ibo;
   22.95 +	mutable bool wire_ibo_valid;
   22.96 +
   22.97 +	// axis-aligned bounding box
   22.98 +	mutable AABox aabb;
   22.99 +	mutable bool aabb_valid;
  22.100 +
  22.101 +	// bounding sphere
  22.102 +	mutable Sphere bsph;
  22.103 +	mutable bool bsph_valid;
  22.104 +
  22.105 +	// keeps the last intersected face
  22.106 +	mutable Triangle hitface;
  22.107 +	// keeps the last intersected vertex position
  22.108 +	mutable Vector3 hitvert;
  22.109 +
  22.110 +	void calc_aabb();
  22.111 +	void calc_bsph();
  22.112 +
  22.113 +	static unsigned int intersect_mode;
  22.114 +	static float vertex_sel_dist;
  22.115 +
  22.116 +	static float vis_vecsize;
  22.117 +
  22.118 +	/// update the VBOs after data has changed (invalid vbo/ibo)
  22.119 +	void update_buffers();
  22.120 +	/// construct/update the wireframe index buffer (called from draw_wire).
  22.121 +	void update_wire_ibo();
  22.122 +
  22.123 +
  22.124 +public:
  22.125 +	Mesh();
  22.126 +	~Mesh();
  22.127 +
  22.128 +	void set_name(const char *name);
  22.129 +	const char *get_name() const;
  22.130 +
  22.131 +	bool has_attrib(int attr) const;
  22.132 +
  22.133 +	// clears everything about this mesh, and returns to the newly constructed state
  22.134 +	void clear();
  22.135 +
  22.136 +	// access the vertex attribute data
  22.137 +	// if vdata == 0, space is just allocated
  22.138 +	float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo
  22.139 +	float *get_attrib_data(int attrib);	// invalidates vbo
  22.140 +	const float *get_attrib_data(int attrib) const;
  22.141 +
  22.142 +	// simple access to any particular attribute
  22.143 +	void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo
  22.144 +	Vector4 get_attrib(int attrib, int idx) const;
  22.145 +
  22.146 +	// ... same for index data
  22.147 +	unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo
  22.148 +	unsigned int *get_index_data();	// invalidates ibo
  22.149 +	const unsigned int *get_index_data() const;
  22.150 +
  22.151 +	void append(const Mesh &mesh);
  22.152 +
  22.153 +	// immediate-mode style mesh construction interface
  22.154 +	void vertex(float x, float y, float z);
  22.155 +	void normal(float nx, float ny, float nz);
  22.156 +	void tangent(float tx, float ty, float tz);
  22.157 +	void texcoord(float u, float v, float w);
  22.158 +	void boneweights(float w1, float w2, float w3, float w4);
  22.159 +	void boneidx(int idx1, int idx2, int idx3, int idx4);
  22.160 +
  22.161 +	/* apply a transformation to the vertices and its inverse-transpose
  22.162 +	 * to the normals and tangents.
  22.163 +	 */
  22.164 +	void apply_xform(const Matrix4x4 &xform);
  22.165 +	void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform);
  22.166 +
  22.167 +	// adds a bone and returns its index
  22.168 +	int add_bone(XFormNode *bone);
  22.169 +	const XFormNode *get_bone(int idx) const;
  22.170 +	int get_bones_count() const;
  22.171 +
  22.172 +	// access the shader attribute locations
  22.173 +	static void set_attrib_location(int attr, int loc);
  22.174 +	static int get_attrib_location(int attr);
  22.175 +	static void clear_attrib_locations();
  22.176 +
  22.177 +	static void set_vis_vecsize(float sz);
  22.178 +	static float get_vis_vecsize();
  22.179 +
  22.180 +	void draw() const;
  22.181 +	void draw_wire() const;
  22.182 +	void draw_vertices() const;
  22.183 +	void draw_normals() const;
  22.184 +	void draw_tangents() const;
  22.185 +
  22.186 +	/** get the bounding box in local space. The result will be cached, and subsequent
  22.187 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  22.188 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  22.189 +	 * @{ */
  22.190 +	void get_aabbox(Vector3 *vmin, Vector3 *vmax) const;
  22.191 +	const AABox &get_aabbox() const;
  22.192 +	/// @}
  22.193 +
  22.194 +	/** get the bounding sphere in local space. The result will be cached, and subsequent
  22.195 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  22.196 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  22.197 +	 * @{ */
  22.198 +	float get_bsphere(Vector3 *center, float *rad) const;
  22.199 +	const Sphere &get_bsphere() const;
  22.200 +
  22.201 +	static void set_intersect_mode(unsigned int mode);
  22.202 +	static unsigned int get_intersect_mode();
  22.203 +	static void set_vertex_select_distance(float dist);
  22.204 +	static float get_vertex_select_distance();
  22.205 +
  22.206 +	/** Find the intersection between the mesh and a ray.
  22.207 +	 * XXX Brute force at the moment, not intended to be used for anything other than picking in tools.
  22.208 +	 *     If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it!
  22.209 +	 */
  22.210 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
  22.211 +};
  22.212 +
  22.213 +#endif	// MESH_H_
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/src/object.cc	Sun Aug 24 09:41:24 2014 +0300
    23.3 @@ -0,0 +1,285 @@
    23.4 +#include <float.h>
    23.5 +#include "object.h"
    23.6 +#include "opengl.h"
    23.7 +#include "unistate.h"
    23.8 +#include "logger.h"
    23.9 +
   23.10 +
   23.11 +static void destroy_all_rec(XFormNode *node);
   23.12 +static void get_all_meshes_rec(XFormNode *node, std::list<Mesh*> *reslist);
   23.13 +
   23.14 +DrawMode Object::draw_mode = DRAW_DEFAULT;
   23.15 +
   23.16 +Object::Object()
   23.17 +{
   23.18 +	mesh = 0;
   23.19 +}
   23.20 +
   23.21 +void Object::destroy_all()
   23.22 +{
   23.23 +	destroy_all_rec(this);
   23.24 +}
   23.25 +
   23.26 +static void destroy_all_rec(XFormNode *node)
   23.27 +{
   23.28 +	if(!node) {
   23.29 +		return;
   23.30 +	}
   23.31 +
   23.32 +	for(int i=0; i<node->get_children_count(); i++) {
   23.33 +		destroy_all_rec(node->get_child(i));
   23.34 +	}
   23.35 +	delete node;
   23.36 +}
   23.37 +
   23.38 +void Object::set_mesh(Mesh *m)
   23.39 +{
   23.40 +	mesh = m;
   23.41 +}
   23.42 +
   23.43 +Mesh *Object::get_mesh()
   23.44 +{
   23.45 +	return mesh;
   23.46 +}
   23.47 +
   23.48 +const Mesh *Object::get_mesh() const
   23.49 +{
   23.50 +	return mesh;
   23.51 +}
   23.52 +
   23.53 +std::list<Mesh*> Object::get_all_meshes()
   23.54 +{
   23.55 +	std::list<Mesh*> meshes;
   23.56 +	get_all_meshes_rec(this, &meshes);
   23.57 +	return meshes;
   23.58 +}
   23.59 +
   23.60 +std::list<const Mesh*> Object::get_all_meshes() const
   23.61 +{
   23.62 +	std::list<const Mesh*> meshes;
   23.63 +	get_all_meshes_rec((Object*)this, (std::list<Mesh*>*)&meshes);
   23.64 +	return meshes;
   23.65 +}
   23.66 +
   23.67 +static void get_all_meshes_rec(XFormNode *node, std::list<Mesh*> *reslist)
   23.68 +{
   23.69 +	if(!node) {
   23.70 +		return;
   23.71 +	}
   23.72 +
   23.73 +	Object *obj = dynamic_cast<Object*>(node);
   23.74 +	if(obj) {
   23.75 +		Mesh *mesh = obj->get_mesh();
   23.76 +		if(mesh) {
   23.77 +			reslist->push_back(mesh);
   23.78 +		}
   23.79 +	}
   23.80 +
   23.81 +	for(int i=0; i<node->get_children_count(); i++) {
   23.82 +		get_all_meshes_rec(node->get_child(i), reslist);
   23.83 +	}
   23.84 +}
   23.85 +
   23.86 +AABox Object::get_aabbox() const
   23.87 +{
   23.88 +	AABox box;
   23.89 +
   23.90 +	if(mesh) {
   23.91 +		box = mesh->get_aabbox();
   23.92 +	} else {
   23.93 +		box.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
   23.94 +		box.max = -box.min;
   23.95 +	}
   23.96 +
   23.97 +	int num_children = get_children_count();
   23.98 +	for(int i=0; i<num_children; i++) {
   23.99 +		const Object *obj = dynamic_cast<const Object*>(get_child(i));
  23.100 +		if(obj) {
  23.101 +			AABox child_box = obj->get_aabbox();
  23.102 +			box.set_union(&box, &child_box);
  23.103 +		}
  23.104 +	}
  23.105 +	return box;
  23.106 +}
  23.107 +
  23.108 +Sphere Object::get_bsphere() const
  23.109 +{
  23.110 +	Sphere sph;
  23.111 +	bool valid = false;
  23.112 +
  23.113 +	if(mesh) {
  23.114 +		sph = mesh->get_bsphere();
  23.115 +		valid = true;
  23.116 +	} else {
  23.117 +		sph.radius = 0.0;
  23.118 +	}
  23.119 +
  23.120 +	int num_children = get_children_count();
  23.121 +	for(int i=0; i<num_children; i++) {
  23.122 +		const Object *obj = dynamic_cast<const Object*>(get_child(i));
  23.123 +		if(obj) {
  23.124 +			Sphere child_sph = obj->get_bsphere();
  23.125 +			if(valid) {
  23.126 +				sph.set_union(&sph, &child_sph);
  23.127 +			} else {
  23.128 +				sph = child_sph;
  23.129 +				valid = true;
  23.130 +			}
  23.131 +		}
  23.132 +	}
  23.133 +
  23.134 +	return sph;
  23.135 +}
  23.136 +
  23.137 +/*static const char *attr_name[] = {
  23.138 +	"attr_vertex",
  23.139 +	"attr_normal",
  23.140 +	"attr_tangent",
  23.141 +	"attr_texcoord",
  23.142 +	"attr_boneweights",
  23.143 +	"attr_boneidx"
  23.144 +};*/
  23.145 +
  23.146 +void Object::draw(long msec) const
  23.147 +{
  23.148 +	Matrix4x4 xform;
  23.149 +	get_xform(msec, &xform);
  23.150 +
  23.151 +	set_world_matrix(xform);
  23.152 +
  23.153 +	if(mesh) {
  23.154 +		/*unsigned int prog = sdrprog;
  23.155 +
  23.156 +		if(mesh->get_bones_count() > 0) {
  23.157 +			prog = sdrprog_skin;
  23.158 +		}
  23.159 +
  23.160 +		glUseProgram(prog);
  23.161 +		// get all the attribute locations
  23.162 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  23.163 +			int loc = glGetAttribLocation(prog, attr_name[i]);
  23.164 +			if(loc != -1) {
  23.165 +				Mesh::set_attrib_location(i, loc);
  23.166 +			}
  23.167 +		}
  23.168 +
  23.169 +		setup_bones(msec);
  23.170 +
  23.171 +		glUseProgram(prog);*/
  23.172 +
  23.173 +		material.setup();
  23.174 +		setup_unistate();	// set all state uniforms
  23.175 +
  23.176 +		switch(Object::draw_mode) {
  23.177 +		case DRAW_WIREFRAME:
  23.178 +			mesh->draw_wire();
  23.179 +			break;
  23.180 +
  23.181 +		case DRAW_VERTICES:
  23.182 +			mesh->draw_vertices();
  23.183 +			break;
  23.184 +
  23.185 +		case DRAW_DEFAULT:
  23.186 +		default:
  23.187 +			mesh->draw();
  23.188 +		}
  23.189 +	}
  23.190 +
  23.191 +	int num_children = get_children_count();
  23.192 +	for(int i=0; i<num_children; i++) {
  23.193 +		const Object *obj = dynamic_cast<const Object*>(get_child(i));
  23.194 +		if(obj) {
  23.195 +			obj->draw(msec);
  23.196 +		}
  23.197 +	}
  23.198 +}
  23.199 +
  23.200 +
  23.201 +bool Object::intersect(const Ray &inray, HitPoint *hit) const
  23.202 +{
  23.203 +	Ray ray = inray;
  23.204 +	Matrix4x4 xform, inv_xform;
  23.205 +	get_xform(ray.time, &xform/*, &inv_xform*/);
  23.206 +	ray.transform(xform.inverse());	// TODO find out what's wrong with get_xform's inv_xform and use that
  23.207 +
  23.208 +	HitPoint nearest_hit;
  23.209 +	nearest_hit.dist = FLT_MAX;
  23.210 +	nearest_hit.obj = 0;
  23.211 +
  23.212 +	if(mesh) {
  23.213 +		if(mesh->intersect(ray, hit ? &nearest_hit : 0)) {
  23.214 +			if(!hit) {
  23.215 +				return true;
  23.216 +			}
  23.217 +
  23.218 +			if(Mesh::get_intersect_mode() & ISECT_FACE) {
  23.219 +				Triangle *face = (Triangle*)nearest_hit.obj;
  23.220 +				face->transform(xform);
  23.221 +			} else if(Mesh::get_intersect_mode() & ISECT_VERTICES) {
  23.222 +				Vector3 *v = (Vector3*)nearest_hit.obj;
  23.223 +				v->transform(xform);
  23.224 +			} else {
  23.225 +				nearest_hit.obj = this;
  23.226 +			}
  23.227 +		}
  23.228 +	}
  23.229 +
  23.230 +	int num_children = get_children_count();
  23.231 +	for(int i=0; i<num_children; i++) {
  23.232 +		const Object *obj = dynamic_cast<const Object*>(get_child(i));
  23.233 +
  23.234 +		HitPoint chit;
  23.235 +		if(obj && obj->intersect(inray, hit ? &chit : 0)) {
  23.236 +			if(!hit) {
  23.237 +				return true;
  23.238 +			}
  23.239 +
  23.240 +			if(chit.dist < nearest_hit.dist) {
  23.241 +				nearest_hit = chit;
  23.242 +			}
  23.243 +		}
  23.244 +	}
  23.245 +
  23.246 +	if(nearest_hit.obj) {
  23.247 +		if(hit) {
  23.248 +			*hit = nearest_hit;
  23.249 +		}
  23.250 +		return true;
  23.251 +	}
  23.252 +	return false;
  23.253 +}
  23.254 +
  23.255 +
  23.256 +bool Object::setup_bones(long msec) const
  23.257 +{
  23.258 +	int num_bones;
  23.259 +	if(!mesh || !(num_bones = mesh->get_bones_count())) {
  23.260 +		return false;
  23.261 +	}
  23.262 +
  23.263 +	/*char uniname[32];
  23.264 +
  23.265 +	for(int i=0; i<num_bones; i++) {
  23.266 +		const XFormNode *bone = mesh->get_bone(i);
  23.267 +
  23.268 +		Matrix4x4 xform;
  23.269 +		bone->get_xform(msec, &xform);
  23.270 +
  23.271 +		xform = xform * bone->get_bone_matrix();
  23.272 +
  23.273 +		sprintf(uniname, "bone_xform[%d]", i);
  23.274 +		int loc = glGetUniformLocation(sdrprog_skin, uniname);
  23.275 +		if(loc == -1) {
  23.276 +			return false;
  23.277 +		}
  23.278 +		glUniformMatrix4fv(loc, 1, GL_TRUE, xform[0]);
  23.279 +	}*/
  23.280 +	return true;
  23.281 +}
  23.282 +
  23.283 +DrawMode Object::set_draw_mode(DrawMode mode)
  23.284 +{
  23.285 +	DrawMode prev = Object::draw_mode;
  23.286 +	Object::draw_mode = mode;
  23.287 +	return prev;
  23.288 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/object.h	Sun Aug 24 09:41:24 2014 +0300
    24.3 @@ -0,0 +1,51 @@
    24.4 +#ifndef OBJECT_H_
    24.5 +#define OBJECT_H_
    24.6 +
    24.7 +#include <list>
    24.8 +#include "xform_node.h"
    24.9 +#include "mesh.h"
   24.10 +#include "material.h"
   24.11 +
   24.12 +enum DrawMode {
   24.13 +	DRAW_DEFAULT,
   24.14 +	DRAW_WIREFRAME,
   24.15 +	DRAW_VERTICES
   24.16 +};
   24.17 +
   24.18 +
   24.19 +class Object : public XFormNode {
   24.20 +private:
   24.21 +	Mesh *mesh;	///< no ownership, just keeping the pointer around
   24.22 +	static DrawMode draw_mode;
   24.23 +
   24.24 +	bool setup_bones(long msec) const;
   24.25 +
   24.26 +public:
   24.27 +	Material material;
   24.28 +
   24.29 +	Object();
   24.30 +
   24.31 +	/// destroy this object and all the hierarchy of objects hanging below it
   24.32 +	void destroy_all();
   24.33 +
   24.34 +	void set_mesh(Mesh *m);
   24.35 +	Mesh *get_mesh();
   24.36 +	const Mesh *get_mesh() const;
   24.37 +
   24.38 +	/// get all the meshes of the subtree rooted in this object @{
   24.39 +	std::list<Mesh*> get_all_meshes();
   24.40 +	std::list<const Mesh*> get_all_meshes() const;
   24.41 +	/// @}
   24.42 +
   24.43 +	AABox get_aabbox() const;
   24.44 +	Sphere get_bsphere() const;
   24.45 +
   24.46 +	void draw(long msec = 0) const;
   24.47 +
   24.48 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   24.49 +
   24.50 +	/// this is mostly for tools, to allow drawing only the wireframe or vertices
   24.51 +	static DrawMode set_draw_mode(DrawMode mode);
   24.52 +};
   24.53 +
   24.54 +#endif	// OBJECT_H_
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/scene.cc	Sun Aug 24 09:41:24 2014 +0300
    25.3 @@ -0,0 +1,34 @@
    25.4 +#include "scene.h"
    25.5 +#include "opengl.h"
    25.6 +
    25.7 +Scene::~Scene()
    25.8 +{
    25.9 +	destroy();
   25.10 +}
   25.11 +
   25.12 +void Scene::destroy()
   25.13 +{
   25.14 +	for(size_t i=0; i<objects.size(); i++) {
   25.15 +		delete objects[i];
   25.16 +	}
   25.17 +	objects.clear();
   25.18 +
   25.19 +	for(size_t i=0; i<meshes.size(); i++) {
   25.20 +		delete meshes[i];
   25.21 +	}
   25.22 +	meshes.clear();
   25.23 +}
   25.24 +
   25.25 +void Scene::draw(long msec) const
   25.26 +{
   25.27 +	for(size_t i=0; i<objects.size(); i++) {
   25.28 +		objects[i]->draw(msec);
   25.29 +	}
   25.30 +
   25.31 +	// if there are no objects in the scene, just draw the meshes instead
   25.32 +	if(objects.empty()) {
   25.33 +		for(size_t i=0; i<meshes.size(); i++) {
   25.34 +			meshes[i]->draw();
   25.35 +		}
   25.36 +	}
   25.37 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/scene.h	Sun Aug 24 09:41:24 2014 +0300
    26.3 @@ -0,0 +1,25 @@
    26.4 +#ifndef SCENE_H_
    26.5 +#define SCENE_H_
    26.6 +
    26.7 +#include <vector>
    26.8 +#include "object.h"
    26.9 +#include "light.h"
   26.10 +#include "camera.h"
   26.11 +
   26.12 +class Scene {
   26.13 +public:
   26.14 +	std::vector<Object*> objects;
   26.15 +	std::vector<Mesh*> meshes;
   26.16 +	std::vector<Light*> lights;
   26.17 +	std::vector<Camera*> cameras;
   26.18 +
   26.19 +	// nodes can be objects, lights, cameras, or just dummy nodes
   26.20 +	std::vector<XFormNode*> nodes;
   26.21 +
   26.22 +	~Scene();
   26.23 +	void destroy();
   26.24 +
   26.25 +	void draw(long msec = 0) const;
   26.26 +};
   26.27 +
   26.28 +#endif	// SCENE_H_
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/src/shader.cc	Sun Aug 24 09:41:24 2014 +0300
    27.3 @@ -0,0 +1,671 @@
    27.4 +#include <stdio.h>
    27.5 +#include <string.h>
    27.6 +#include <stdarg.h>
    27.7 +#include <errno.h>
    27.8 +#include "opengl.h"
    27.9 +#include "shader.h"
   27.10 +#include "mesh.h"
   27.11 +#include "logger.h"
   27.12 +#include "unistate.h"
   27.13 +
   27.14 +#ifdef _MSC_VER
   27.15 +#include <malloc.h>
   27.16 +#else
   27.17 +#include <alloca.h>
   27.18 +#endif
   27.19 +
   27.20 +#ifdef __GLEW_H__
   27.21 +#define HAVE_GEOMETRY_SHADER
   27.22 +#define HAVE_TESSELATION_SHADER
   27.23 +#endif
   27.24 +
   27.25 +static std::string read_source(const char *fname);
   27.26 +static void bind_standard_attr(const ShaderProg *prog);
   27.27 +
   27.28 +ShaderProg *ShaderProg::current;
   27.29 +
   27.30 +void bind_shader(const ShaderProg *sdr)
   27.31 +{
   27.32 +	if(sdr) {
   27.33 +		sdr->bind();
   27.34 +	} else {
   27.35 +#ifndef GL_ES_VERSION_2_0
   27.36 +		glUseProgram(0);
   27.37 +		ShaderProg::current = 0;
   27.38 +#endif
   27.39 +	}
   27.40 +}
   27.41 +
   27.42 +const ShaderProg *get_current_shader()
   27.43 +{
   27.44 +	return ShaderProg::current;
   27.45 +}
   27.46 +
   27.47 +Shader::Shader()
   27.48 +{
   27.49 +	sdr = type = 0;
   27.50 +}
   27.51 +
   27.52 +Shader::~Shader()
   27.53 +{
   27.54 +	destroy();
   27.55 +}
   27.56 +
   27.57 +unsigned int Shader::get_id() const
   27.58 +{
   27.59 +	return sdr;
   27.60 +}
   27.61 +
   27.62 +void Shader::set_name(const char *name)
   27.63 +{
   27.64 +	this->name = std::string(name);
   27.65 +}
   27.66 +
   27.67 +const char *Shader::get_name() const
   27.68 +{
   27.69 +	return name.c_str();
   27.70 +}
   27.71 +
   27.72 +bool Shader::create(const char *src, unsigned int type)
   27.73 +{
   27.74 +#if !GL_ES_VERSION_2_0
   27.75 +	const char *src_arr[] = {src};
   27.76 +#else
   27.77 +	const char *src_arr[] = { "precision mediump float; ", src };
   27.78 +#endif
   27.79 +
   27.80 +	// keep a copy of the source code
   27.81 +	this->src = std::string(src);
   27.82 +
   27.83 +	if(!sdr) {
   27.84 +		sdr = glCreateShader(type);
   27.85 +	}
   27.86 +
   27.87 +	info_log("compiling shader: %s... ", name.c_str());
   27.88 +
   27.89 +	glShaderSource(sdr, sizeof src_arr / sizeof *src_arr, src_arr, 0);
   27.90 +	glCompileShader(sdr);
   27.91 +
   27.92 +	int status;
   27.93 +	glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
   27.94 +
   27.95 +	info_log(status ? "success\n" : "failed\n");
   27.96 +
   27.97 +	int info_len;
   27.98 +	glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
   27.99 +	if(info_len > 1) {
  27.100 +		char *buf = (char*)alloca(info_len);
  27.101 +		glGetShaderInfoLog(sdr, info_len, 0, buf);
  27.102 +		buf[info_len - 1] = 0;
  27.103 +
  27.104 +		if(status) {
  27.105 +			info_log("%s\n", buf);
  27.106 +		} else {
  27.107 +			error_log("%s\n", buf);
  27.108 +		}
  27.109 +	}
  27.110 +
  27.111 +	return status == GL_TRUE;
  27.112 +}
  27.113 +
  27.114 +void Shader::destroy()
  27.115 +{
  27.116 +	if(sdr) {
  27.117 +		glDeleteShader(sdr);
  27.118 +	}
  27.119 +	sdr = type = 0;
  27.120 +
  27.121 +	src.clear();
  27.122 +	name.clear();
  27.123 +}
  27.124 +
  27.125 +static std::string read_source(const char *fname)
  27.126 +{
  27.127 +	FILE *fp;
  27.128 +
  27.129 +	if(!(fp = fopen(fname, "rb"))) {
  27.130 +		error_log("failed to load shader: %s: %s\n", fname, strerror(errno));
  27.131 +		return std::string();
  27.132 +	}
  27.133 +
  27.134 +	fseek(fp, 0, SEEK_END);
  27.135 +	long sz = ftell(fp);
  27.136 +	rewind(fp);
  27.137 +
  27.138 +	char *src = (char*)alloca(sz + 1);
  27.139 +	if(fread(src, 1, sz, fp) < (size_t)sz) {
  27.140 +		error_log("failed to load shader: %s: %s\n", fname, strerror(errno));
  27.141 +		fclose(fp);
  27.142 +		delete [] src;
  27.143 +		return std::string();
  27.144 +	}
  27.145 +	src[sz] = 0;
  27.146 +	fclose(fp);
  27.147 +
  27.148 +	return std::string(src);
  27.149 +}
  27.150 +
  27.151 +bool Shader::load(const char *fname, unsigned int type)
  27.152 +{
  27.153 +	std::string src = read_source(fname);
  27.154 +	if(src.empty()) {
  27.155 +		return false;
  27.156 +	}
  27.157 +	set_name(fname);
  27.158 +	return create(src.c_str(), type);
  27.159 +}
  27.160 +
  27.161 +// ---- shader program ----
  27.162 +ShaderProg::ShaderProg()
  27.163 +{
  27.164 +	prog = 0;
  27.165 +	must_link = true;
  27.166 +}
  27.167 +
  27.168 +ShaderProg::~ShaderProg()
  27.169 +{
  27.170 +	destroy();
  27.171 +}
  27.172 +
  27.173 +unsigned int ShaderProg::get_id() const
  27.174 +{
  27.175 +	return prog;
  27.176 +}
  27.177 +
  27.178 +bool ShaderProg::create(const char *src, unsigned int type, ...)
  27.179 +{
  27.180 +	va_list ap;
  27.181 +
  27.182 +	va_start(ap, type);
  27.183 +	bool res = create(src, type, ap);
  27.184 +	va_end(ap);
  27.185 +
  27.186 +	return res;
  27.187 +}
  27.188 +
  27.189 +bool ShaderProg::create(const char *src, unsigned int type, va_list ap)
  27.190 +{
  27.191 +	destroy();
  27.192 +	prog = glCreateProgram();
  27.193 +
  27.194 +	while(src) {
  27.195 +		Shader *sdr = new Shader;
  27.196 +		if(!sdr->create(src, type)) {
  27.197 +			va_end(ap);
  27.198 +			return false;
  27.199 +		}
  27.200 +		add_shader(sdr);
  27.201 +		src = va_arg(ap, const char*);
  27.202 +		type = va_arg(ap, unsigned int);
  27.203 +	}
  27.204 +
  27.205 +	return link();
  27.206 +}
  27.207 +
  27.208 +bool ShaderProg::create(const char *vsrc, const char *psrc)
  27.209 +{
  27.210 +	return create(VSDR(vsrc), PSDR(psrc), 0);
  27.211 +}
  27.212 +
  27.213 +bool ShaderProg::create(Shader *sdr, ...)
  27.214 +{
  27.215 +	va_list ap;
  27.216 +
  27.217 +	va_start(ap, sdr);
  27.218 +	bool res = create(sdr, ap);
  27.219 +	va_end(ap);
  27.220 +
  27.221 +	return res;
  27.222 +}
  27.223 +
  27.224 +bool ShaderProg::create(Shader *sdr, va_list ap)
  27.225 +{
  27.226 +	destroy();
  27.227 +	prog = glCreateProgram();
  27.228 +
  27.229 +	while(sdr) {
  27.230 +		add_shader(sdr);
  27.231 +		sdr = va_arg(ap, Shader*);
  27.232 +	}
  27.233 +	return link();
  27.234 +}
  27.235 +
  27.236 +bool ShaderProg::create(Shader *vsdr, Shader *psdr)
  27.237 +{
  27.238 +	return create(vsdr, psdr, 0);
  27.239 +}
  27.240 +
  27.241 +void ShaderProg::destroy()
  27.242 +{
  27.243 +	if(prog) {
  27.244 +		glDeleteProgram(prog);
  27.245 +	}
  27.246 +	prog = 0;
  27.247 +
  27.248 +	shaders.clear();
  27.249 +	// don't actually destroy the shaders, let the ShaderSet own them
  27.250 +}
  27.251 +
  27.252 +bool ShaderProg::load(const char *fname, unsigned int type, ...)
  27.253 +{
  27.254 +	va_list ap;
  27.255 +	va_start(ap, type);
  27.256 +	bool res = load(fname, type, ap);
  27.257 +	va_end(ap);
  27.258 +
  27.259 +	return res;
  27.260 +}
  27.261 +
  27.262 +bool ShaderProg::load(const char *fname, unsigned int type, va_list ap)
  27.263 +{
  27.264 +	destroy();
  27.265 +	prog = glCreateProgram();
  27.266 +
  27.267 +	while(fname) {
  27.268 +		Shader *sdr = new Shader;
  27.269 +		if(!sdr->load(fname, type)) {
  27.270 +			delete sdr;
  27.271 +			return false;
  27.272 +		}
  27.273 +		add_shader(sdr);
  27.274 +
  27.275 +		if((fname = va_arg(ap, const char*))) {
  27.276 +			type = va_arg(ap, unsigned int);
  27.277 +		}
  27.278 +	}
  27.279 +
  27.280 +	return link();
  27.281 +}
  27.282 +
  27.283 +bool ShaderProg::load(const char *vfname, const char *pfname)
  27.284 +{
  27.285 +	return load(VSDR(vfname), PSDR(pfname), 0);
  27.286 +}
  27.287 +
  27.288 +void ShaderProg::add_shader(Shader *sdr)
  27.289 +{
  27.290 +	glAttachShader(prog, sdr->get_id());
  27.291 +}
  27.292 +
  27.293 +bool ShaderProg::link() const
  27.294 +{
  27.295 +	bind_standard_attr(this);
  27.296 +
  27.297 +	CHECKGLERR;
  27.298 +	info_log("linking program ... ");
  27.299 +	glLinkProgram(prog);
  27.300 +
  27.301 +	int status;
  27.302 +	glGetProgramiv(prog, GL_LINK_STATUS, &status);
  27.303 +
  27.304 +	info_log(status ? "success\n" : "failed\n");
  27.305 +
  27.306 +	int info_len;
  27.307 +	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
  27.308 +	if(info_len > 1) {
  27.309 +		char *buf = (char*)alloca(info_len);
  27.310 +		glGetProgramInfoLog(prog, info_len, 0, buf);
  27.311 +		buf[info_len - 1] = 0;
  27.312 +
  27.313 +		if(status) {
  27.314 +			info_log("%s\n", buf);
  27.315 +		} else {
  27.316 +			error_log("%s\n", buf);
  27.317 +		}
  27.318 +	}
  27.319 +
  27.320 +	if(status) {
  27.321 +		must_link = false;
  27.322 +		cache_state_uniforms();
  27.323 +		return true;
  27.324 +	}
  27.325 +	return false;
  27.326 +}
  27.327 +
  27.328 +void ShaderProg::bind() const
  27.329 +{
  27.330 +	CHECKGLERR;
  27.331 +	if(must_link) {
  27.332 +		if(!link()) {
  27.333 +			return;
  27.334 +		}
  27.335 +	}
  27.336 +	CHECKGLERR;
  27.337 +	glUseProgram(prog);
  27.338 +	ShaderProg::current = (ShaderProg*)this;
  27.339 +
  27.340 +	setup_state_uniforms();
  27.341 +}
  27.342 +
  27.343 +
  27.344 +int ShaderProg::get_attrib_location(const char *name) const
  27.345 +{
  27.346 +	glUseProgram(prog);
  27.347 +	return glGetAttribLocation(prog, name);
  27.348 +}
  27.349 +
  27.350 +void ShaderProg::set_attrib_location(const char *name, int loc) const
  27.351 +{
  27.352 +	glBindAttribLocation(prog, loc, name);
  27.353 +	must_link = true;
  27.354 +}
  27.355 +
  27.356 +int ShaderProg::get_uniform_location(const char *name) const
  27.357 +{
  27.358 +	glUseProgram(prog);
  27.359 +	return glGetUniformLocation(prog, name);
  27.360 +}
  27.361 +
  27.362 +bool ShaderProg::set_uniform(int loc, int val) const
  27.363 +{
  27.364 +	glUseProgram(prog);
  27.365 +	if(loc >= 0) {
  27.366 +		glUniform1i(loc, val);
  27.367 +		return true;
  27.368 +	}
  27.369 +	return false;
  27.370 +}
  27.371 +
  27.372 +bool ShaderProg::set_uniform(int loc, float val) const
  27.373 +{
  27.374 +	glUseProgram(prog);
  27.375 +	if(loc >= 0) {
  27.376 +		glUniform1f(loc, val);
  27.377 +		return true;
  27.378 +	}
  27.379 +	return false;
  27.380 +}
  27.381 +
  27.382 +bool ShaderProg::set_uniform(int loc, const Vector2 &v) const
  27.383 +{
  27.384 +	glUseProgram(prog);
  27.385 +	if(loc >= 0) {
  27.386 +		glUniform2f(loc, v.x, v.y);
  27.387 +		return true;
  27.388 +	}
  27.389 +	return false;
  27.390 +}
  27.391 +
  27.392 +bool ShaderProg::set_uniform(int loc, const Vector3 &v) const
  27.393 +{
  27.394 +	glUseProgram(prog);
  27.395 +	if(loc >= 0) {
  27.396 +		glUniform3f(loc, v.x, v.y, v.z);
  27.397 +		return true;
  27.398 +	}
  27.399 +	return false;
  27.400 +}
  27.401 +
  27.402 +bool ShaderProg::set_uniform(int loc, const Vector4 &v) const
  27.403 +{
  27.404 +	glUseProgram(prog);
  27.405 +	if(loc >= 0) {
  27.406 +		glUniform4f(loc, v.x, v.y, v.z, v.w);
  27.407 +		return true;
  27.408 +	}
  27.409 +	return false;
  27.410 +}
  27.411 +
  27.412 +bool ShaderProg::set_uniform(int loc, const Matrix3x3 &m) const
  27.413 +{
  27.414 +	glUseProgram(prog);
  27.415 +	if(loc >= 0) {
  27.416 +		glUniformMatrix3fv(loc, 1, GL_TRUE, m[0]);
  27.417 +		return true;
  27.418 +	}
  27.419 +	return false;
  27.420 +}
  27.421 +
  27.422 +bool ShaderProg::set_uniform(int loc, const Matrix4x4 &m) const
  27.423 +{
  27.424 +	glUseProgram(prog);
  27.425 +	if(loc >= 0) {
  27.426 +		glUniformMatrix4fv(loc, 1, GL_TRUE, m[0]);
  27.427 +		return true;
  27.428 +	}
  27.429 +	return false;
  27.430 +}
  27.431 +
  27.432 +
  27.433 +bool ShaderProg::set_uniform(const char *name, int val) const
  27.434 +{
  27.435 +	return set_uniform(get_uniform_location(name), val);
  27.436 +}
  27.437 +
  27.438 +bool ShaderProg::set_uniform(const char *name, float val) const
  27.439 +{
  27.440 +	return set_uniform(get_uniform_location(name), val);
  27.441 +}
  27.442 +
  27.443 +bool ShaderProg::set_uniform(const char *name, const Vector2 &v) const
  27.444 +{
  27.445 +	return set_uniform(get_uniform_location(name), v);
  27.446 +}
  27.447 +
  27.448 +bool ShaderProg::set_uniform(const char *name, const Vector3 &v) const
  27.449 +{
  27.450 +	return set_uniform(get_uniform_location(name), v);
  27.451 +}
  27.452 +
  27.453 +bool ShaderProg::set_uniform(const char *name, const Vector4 &v) const
  27.454 +{
  27.455 +	return set_uniform(get_uniform_location(name), v);
  27.456 +}
  27.457 +
  27.458 +bool ShaderProg::set_uniform(const char *name, const Matrix3x3 &m) const
  27.459 +{
  27.460 +	return set_uniform(get_uniform_location(name), m);
  27.461 +}
  27.462 +
  27.463 +bool ShaderProg::set_uniform(const char *name, const Matrix4x4 &m) const
  27.464 +{
  27.465 +	return set_uniform(get_uniform_location(name), m);
  27.466 +}
  27.467 +
  27.468 +static StType unist_type(GLenum type)
  27.469 +{
  27.470 +	switch(type) {
  27.471 +	case GL_FLOAT:
  27.472 +		return ST_FLOAT;
  27.473 +	case GL_FLOAT_VEC2:
  27.474 +		return ST_FLOAT2;
  27.475 +	case GL_FLOAT_VEC3:
  27.476 +		return ST_FLOAT3;
  27.477 +	case GL_FLOAT_VEC4:
  27.478 +		return ST_FLOAT4;
  27.479 +	case GL_INT:
  27.480 +	case GL_SAMPLER_2D:
  27.481 +	case GL_SAMPLER_CUBE:
  27.482 +#if !GL_ES_VERSION_2_0
  27.483 +	case GL_SAMPLER_1D:
  27.484 +	case GL_SAMPLER_3D:
  27.485 +	case GL_SAMPLER_1D_SHADOW:
  27.486 +	case GL_SAMPLER_2D_SHADOW:
  27.487 +#endif
  27.488 +		return ST_INT;
  27.489 +	case GL_INT_VEC2:
  27.490 +		return ST_INT2;
  27.491 +	case GL_INT_VEC3:
  27.492 +		return ST_INT3;
  27.493 +	case GL_INT_VEC4:
  27.494 +		return ST_INT4;
  27.495 +	case GL_FLOAT_MAT3:
  27.496 +		return ST_MATRIX3;
  27.497 +	case GL_FLOAT_MAT4:
  27.498 +		return ST_MATRIX4;
  27.499 +	default:
  27.500 +		break;
  27.501 +	}
  27.502 +	return ST_UNKNOWN;
  27.503 +}
  27.504 +
  27.505 +void ShaderProg::cache_state_uniforms() const
  27.506 +{
  27.507 +	if(!glIsProgram(prog)) {
  27.508 +		return;
  27.509 +	}
  27.510 +
  27.511 +	int num_uni;
  27.512 +	glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uni);
  27.513 +
  27.514 +	char name[256];
  27.515 +	for(int i=0; i<num_uni; i++) {
  27.516 +		GLint sz;
  27.517 +		GLenum type;
  27.518 +		glGetActiveUniform(prog, i, sizeof name - 1, 0, &sz, &type, name);
  27.519 +
  27.520 +		if(strstr(name, "st_") == name) {
  27.521 +			StateLocCache s;
  27.522 +			s.sidx = add_unistate(name, unist_type(type));
  27.523 +			s.loc = glGetUniformLocation(prog, name);
  27.524 +			stloc_cache.push_back(s);
  27.525 +		}
  27.526 +	}
  27.527 +}
  27.528 +
  27.529 +void ShaderProg::setup_state_uniforms() const
  27.530 +{
  27.531 +	for(size_t i=0; i<stloc_cache.size(); i++) {
  27.532 +		setup_unistate(stloc_cache[i].sidx, this, stloc_cache[i].loc);
  27.533 +		CHECKGLERR;
  27.534 +	}
  27.535 +}
  27.536 +
  27.537 +
  27.538 +// ---- ShaderSet ----
  27.539 +static Shader *load_shader(const char *fname, unsigned int type)
  27.540 +{
  27.541 +	Shader *sdr = new Shader;
  27.542 +	if(!sdr->load(fname, type)) {
  27.543 +		delete sdr;
  27.544 +		return 0;
  27.545 +	}
  27.546 +	return sdr;
  27.547 +}
  27.548 +
  27.549 +static Shader *load_vertex_shader(const char *fname)
  27.550 +{
  27.551 +	return load_shader(fname, GL_VERTEX_SHADER);
  27.552 +}
  27.553 +
  27.554 +static Shader *load_pixel_shader(const char *fname)
  27.555 +{
  27.556 +	return load_shader(fname, GL_FRAGMENT_SHADER);
  27.557 +}
  27.558 +
  27.559 +#ifdef HAVE_GEOMETRY_SHADER
  27.560 +static Shader *load_geom_shader(const char *fname)
  27.561 +{
  27.562 +	return load_shader(fname, GL_GEOMETRY_SHADER);
  27.563 +}
  27.564 +#endif
  27.565 +
  27.566 +#ifdef HAVE_TESSELATION_SHADER
  27.567 +static Shader *load_tc_shader(const char *fname)
  27.568 +{
  27.569 +	return load_shader(fname, GL_TESS_CONTROL_SHADER);
  27.570 +}
  27.571 +
  27.572 +static Shader *load_te_shader(const char *fname)
  27.573 +{
  27.574 +	return load_shader(fname, GL_TESS_EVALUATION_SHADER);
  27.575 +}
  27.576 +#endif
  27.577 +
  27.578 +static void destroy_shader(Shader *sdr)
  27.579 +{
  27.580 +	delete sdr;
  27.581 +}
  27.582 +
  27.583 +ShaderSet::ShaderSet(unsigned int type)
  27.584 +	: DataSet<Shader*>(0, destroy_shader)
  27.585 +{
  27.586 +	this->type = type;
  27.587 +
  27.588 +	switch(type) {
  27.589 +	case GL_VERTEX_SHADER:
  27.590 +		load = load_vertex_shader;
  27.591 +		break;
  27.592 +
  27.593 +	case GL_FRAGMENT_SHADER:
  27.594 +		load = load_pixel_shader;
  27.595 +		break;
  27.596 +
  27.597 +#ifdef HAVE_GEOMETRY_SHADER
  27.598 +	case GL_GEOMETRY_SHADER:
  27.599 +		load = load_geom_shader;
  27.600 +		break;
  27.601 +#endif
  27.602 +
  27.603 +#ifdef HAVE_TESSELATION_SHADER
  27.604 +	case GL_TESS_CONTROL_SHADER:
  27.605 +		load = load_tc_shader;
  27.606 +		break;
  27.607 +
  27.608 +	case GL_TESS_EVALUATION_SHADER:
  27.609 +		load = load_te_shader;
  27.610 +		break;
  27.611 +#endif
  27.612 +
  27.613 +	default:
  27.614 +		error_log("ShaderSet constructed with invalid shader type!\n");
  27.615 +	}
  27.616 +}
  27.617 +
  27.618 +static struct { const char *name; int loc; } attr_loc[] = {
  27.619 +	{"attr_vertex", MESH_ATTR_VERTEX},
  27.620 +	{"attr_normal", MESH_ATTR_NORMAL},
  27.621 +	{"attr_tangent", MESH_ATTR_TANGENT},
  27.622 +	{"attr_texcoord", MESH_ATTR_TEXCOORD},
  27.623 +	{"attr_color", MESH_ATTR_COLOR},
  27.624 +	{"attr_boneweights", MESH_ATTR_BONEWEIGHTS},
  27.625 +	{"attr_boneidx", MESH_ATTR_BONEIDX}
  27.626 +};
  27.627 +
  27.628 +static void bind_standard_attr(const ShaderProg *prog)
  27.629 +{
  27.630 +	// we must link once to find out which are the active attributes
  27.631 +	glLinkProgram(prog->get_id());
  27.632 +
  27.633 +	int num_attr;
  27.634 +	glGetProgramiv(prog->get_id(), GL_ACTIVE_ATTRIBUTES, &num_attr);
  27.635 +
  27.636 +	char name[256];
  27.637 +	for(int i=0; i<num_attr; i++) {
  27.638 +		GLint sz;
  27.639 +		GLenum type;
  27.640 +		glGetActiveAttrib(prog->get_id(), i, sizeof name - 1, 0, &sz, &type, name);
  27.641 +
  27.642 +		for(int j=0; j<(int)(sizeof attr_loc / sizeof *attr_loc); j++) {
  27.643 +			if(strcmp(name, attr_loc[j].name) == 0) {
  27.644 +				prog->set_attrib_location(name, attr_loc[j].loc);
  27.645 +			}
  27.646 +		}
  27.647 +	}
  27.648 +}
  27.649 +
  27.650 +
  27.651 +/*
  27.652 +static const char *strtype(unsigned int type)
  27.653 +{
  27.654 +	switch(type) {
  27.655 +	case GL_VERTEX_SHADER:
  27.656 +		return "vertex";
  27.657 +	case GL_FRAGMENT_SHADER:
  27.658 +		return "fragment";
  27.659 +#ifdef HAVE_GEOMETRY_SHADER
  27.660 +	case GL_GEOMETRY_SHADER:
  27.661 +		return "geometry";
  27.662 +#endif
  27.663 +#ifdef HAVE_TESSELATION_SHADER
  27.664 +	case GL_TESS_CONTROL_SHADER:
  27.665 +		return "tesselation control";
  27.666 +	case GL_TESS_EVALUATION_SHADER:
  27.667 +		return "tesselation evaluation";
  27.668 +#endif
  27.669 +	default:
  27.670 +		break;
  27.671 +	}
  27.672 +	return "<unknown>";
  27.673 +}
  27.674 +*/
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/shader.h	Sun Aug 24 09:41:24 2014 +0300
    28.3 @@ -0,0 +1,150 @@
    28.4 +#ifndef SHADER_H_
    28.5 +#define SHADER_H_
    28.6 +
    28.7 +#include <vector>
    28.8 +#include <string>
    28.9 +#include "vmath/vmath.h"
   28.10 +#include "opengl.h"
   28.11 +#include "dataset.h"
   28.12 +
   28.13 +class ShaderProg;
   28.14 +
   28.15 +
   28.16 +void bind_shader(const ShaderProg *sdr);
   28.17 +const ShaderProg *get_current_shader();
   28.18 +
   28.19 +
   28.20 +class Shader {
   28.21 +private:
   28.22 +	unsigned int sdr;
   28.23 +	unsigned int type;
   28.24 +	std::string name, src;
   28.25 +
   28.26 +public:
   28.27 +	Shader();
   28.28 +	~Shader();
   28.29 +
   28.30 +	unsigned int get_id() const;
   28.31 +
   28.32 +	void set_name(const char *name);
   28.33 +	const char *get_name() const;
   28.34 +
   28.35 +	bool create(const char *src, unsigned int type);
   28.36 +	void destroy();
   28.37 +
   28.38 +	bool load(const char *fname, unsigned int type);
   28.39 +
   28.40 +
   28.41 +	// these functions are only meant to be used by the ShaderSet
   28.42 +	static Shader *create_shader();
   28.43 +	static bool load_shader(Shader *sdr, const char *fname);
   28.44 +	static bool done_shader(Shader *sdr, unsigned int type);
   28.45 +	static void destroy_shader(Shader *sdr);
   28.46 +};
   28.47 +
   28.48 +#define VSDR(s)		s, GL_VERTEX_SHADER
   28.49 +#define FSDR(s)		s, GL_FRAGMENT_SHADER
   28.50 +#define PSDR(s)		FSDR(s)
   28.51 +#define GSDR(s)		s, GL_GEOMETRY_SHADER
   28.52 +#define TCSDR(s)	s, GL_TESS_CONTROL_SHADER
   28.53 +#define TESDR(s)	s, GL_TESS_EVALUATION_SHADER
   28.54 +
   28.55 +class ShaderProg {
   28.56 +private:
   28.57 +	unsigned int prog;
   28.58 +	mutable bool must_link;
   28.59 +	std::vector<Shader*> shaders;
   28.60 +
   28.61 +	struct StateLocCache { int sidx, loc; };
   28.62 +	/** a cache of all st_ prefixed uniform locations and their corresponding
   28.63 +	 * index in the global uniform state vector (see unistate.h)
   28.64 +	 */
   28.65 +	mutable std::vector<StateLocCache> stloc_cache;
   28.66 +
   28.67 +	void cache_state_uniforms() const;
   28.68 +	void setup_state_uniforms() const;
   28.69 +
   28.70 +public:
   28.71 +	static ShaderProg *current;
   28.72 +
   28.73 +	ShaderProg();
   28.74 +	~ShaderProg();
   28.75 +
   28.76 +	/// returns the OpenGL object id for this shader program
   28.77 +	unsigned int get_id() const;
   28.78 +
   28.79 +	/** takes a series of shaders, and constructs a program object by linking
   28.80 +	 * them together. Terminate with a null pointer (don't use 0!) */
   28.81 +	bool create(Shader *sdr, ...);
   28.82 +	/// same as above, but with a va_list instead of variable arguments.
   28.83 +	bool create(Shader *sdr, va_list ap);
   28.84 +	/** takes two shaders (vertex and pixel) and constructs a program object by
   28.85 +	 * linking them together. Either one can be null. */
   28.86 +	bool create(Shader *vsdr, Shader *psdr);
   28.87 +
   28.88 +	/** takes a series of shader source/shader type pairs and constructs a program
   28.89 +	 * object by linking them together. Terminate with a null pointer (don't use 0!)
   28.90 +	 * You can use the VSDR, PSDR, GSDR, TCSDR, TESDR convenience macros for passing
   28.91 +	 * the pairs.
   28.92 +	 * Example: create(VSDR(vsrc0), VSDR(vsrc1), PSDR(psrc), NULL);
   28.93 +	 */
   28.94 +	bool create(const char *src, unsigned int type, ...);
   28.95 +	/// same as above, but with a va_list instead of variable arguments.
   28.96 +	bool create(const char *src, unsigned int type, va_list ap);
   28.97 +	/** takes two shaders source strings (vertex and pixel) and constructs
   28.98 +	 * a program object by linking them together. Either one can be null. */
   28.99 +	bool create(const char *vsrc, const char *psrc);
  28.100 +
  28.101 +	void destroy();
  28.102 +
  28.103 +	/** takes a series of shader filename/shader type pairs, loads the shaders and
  28.104 +	 * constructs a program object by linking them together. Terminate with a null
  28.105 +	 * pointer (don't use 0!). You can use the VSDR, PSDR, GSDR, TCSDR, TESDR convenience
  28.106 +	 * macros for passing the pairs.
  28.107 +	 * Example: load(VSDR("vsdr1.glsl"), VSDR("vsdr2.glsl"), PSDR("pixel.glsl"), NULL);
  28.108 +	 */
  28.109 +	bool load(const char *fname, unsigned int type, ...);
  28.110 +	/// same as above, but with a va_list instead of variable arguments.
  28.111 +	bool load(const char *fname, unsigned int type, va_list ap);
  28.112 +	/** takes the filenames of two shader files (vertex and pixel), loads them and
  28.113 +	 * constructs a program object by linking them together. Either one can be null */
  28.114 +	bool load(const char *vsrc, const char *psrc);
  28.115 +
  28.116 +	void add_shader(Shader *sdr);
  28.117 +	bool link() const;
  28.118 +
  28.119 +	void bind() const;
  28.120 +
  28.121 +	int get_attrib_location(const char *name) const;
  28.122 +	void set_attrib_location(const char *name, int loc) const;
  28.123 +
  28.124 +	int get_uniform_location(const char *name) const;
  28.125 +
  28.126 +	bool set_uniform(int loc, int val) const;
  28.127 +	bool set_uniform(int loc, float val) const;
  28.128 +	bool set_uniform(int loc, const Vector2 &v) const;
  28.129 +	bool set_uniform(int loc, const Vector3 &v) const;
  28.130 +	bool set_uniform(int loc, const Vector4 &v) const;
  28.131 +	bool set_uniform(int loc, const Matrix3x3 &m) const;
  28.132 +	bool set_uniform(int loc, const Matrix4x4 &m) const;
  28.133 +
  28.134 +	bool set_uniform(const char *name, int val) const;
  28.135 +	bool set_uniform(const char *name, float val) const;
  28.136 +	bool set_uniform(const char *name, const Vector2 &v) const;
  28.137 +	bool set_uniform(const char *name, const Vector3 &v) const;
  28.138 +	bool set_uniform(const char *name, const Vector4 &v) const;
  28.139 +	bool set_uniform(const char *name, const Matrix3x3 &m) const;
  28.140 +	bool set_uniform(const char *name, const Matrix4x4 &m) const;
  28.141 +
  28.142 +	friend void setup_unistate(const ShaderProg*);
  28.143 +};
  28.144 +
  28.145 +class ShaderSet : public DataSet<Shader*> {
  28.146 +private:
  28.147 +	unsigned int type;
  28.148 +
  28.149 +public:
  28.150 +	ShaderSet(unsigned int type);
  28.151 +};
  28.152 +
  28.153 +#endif	// SHADER_H_
    29.1 --- a/src/texture.cc	Sat Aug 23 12:03:29 2014 +0300
    29.2 +++ b/src/texture.cc	Sun Aug 24 09:41:24 2014 +0300
    29.3 @@ -64,18 +64,16 @@
    29.4  	return img;
    29.5  }
    29.6  
    29.7 +unsigned int Texture::get_type() const
    29.8 +{
    29.9 +	return type;
   29.10 +}
   29.11 +
   29.12  unsigned int Texture::get_texture_id() const
   29.13  {
   29.14  	return tex;
   29.15  }
   29.16  
   29.17 -void Texture::bind(int tunit) const
   29.18 -{
   29.19 -	glActiveTextureARB(GL_TEXTURE0_ARB + tunit);
   29.20 -	glBindTexture(type, tex);
   29.21 -	glActiveTextureARB(GL_TEXTURE0_ARB);
   29.22 -}
   29.23 -
   29.24  bool Texture::load(const char *fname)
   29.25  {
   29.26  	Image image;
   29.27 @@ -86,6 +84,26 @@
   29.28  	return true;
   29.29  }
   29.30  
   29.31 +void bind_texture(const Texture *tex, int tunit)
   29.32 +{
   29.33 +	static unsigned int cur_tex_type[8] = {
   29.34 +		GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D,
   29.35 +		GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D
   29.36 +	};
   29.37 +
   29.38 +	glActiveTextureARB(GL_TEXTURE0_ARB + tunit);
   29.39 +	if(tex) {
   29.40 +		glBindTexture(tex->get_type(), tex->get_texture_id());
   29.41 +		glEnable(tex->get_type());
   29.42 +	} else {
   29.43 +		glDisable(cur_tex_type[tunit]);
   29.44 +	}
   29.45 +	glActiveTextureARB(GL_TEXTURE0_ARB);
   29.46 +
   29.47 +	cur_tex_type[tunit] = tex->get_type();
   29.48 +}
   29.49 +
   29.50 +
   29.51  unsigned int next_pow2(unsigned int x)
   29.52  {
   29.53  	x -= 1;
    30.1 --- a/src/texture.h	Sat Aug 23 12:03:29 2014 +0300
    30.2 +++ b/src/texture.h	Sun Aug 24 09:41:24 2014 +0300
    30.3 @@ -23,12 +23,14 @@
    30.4  	Image &get_image();
    30.5  	const Image &get_image() const;
    30.6  
    30.7 +	unsigned int get_type() const;
    30.8  	unsigned int get_texture_id() const;
    30.9 -	void bind(int tunit = 0) const;
   30.10  
   30.11  	bool load(const char *fname);
   30.12  };
   30.13  
   30.14 +void bind_texture(const Texture *tex, int unit = 0);
   30.15 +
   30.16  unsigned int next_pow2(unsigned int x);
   30.17  
   30.18  #endif	// TEXTURE_H_
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/unistate.cc	Sun Aug 24 09:41:24 2014 +0300
    31.3 @@ -0,0 +1,678 @@
    31.4 +#include <map>
    31.5 +#include <vector>
    31.6 +#include "unistate.h"
    31.7 +#include "shader.h"
    31.8 +#include "logger.h"
    31.9 +
   31.10 +struct StateItem {
   31.11 +	StType type;
   31.12 +
   31.13 +	union {
   31.14 +		int ival[4];
   31.15 +		float fval[16];
   31.16 +	};
   31.17 +	int transpose;	// for matrices
   31.18 +};
   31.19 +
   31.20 +static const char *typestr(StType type);
   31.21 +static int type_nelem(StType type);
   31.22 +static StType float_type(int elem);
   31.23 +static StType int_type(int elem);
   31.24 +
   31.25 +std::vector<StateItem> state;
   31.26 +std::map<std::string, int> stateidx;
   31.27 +
   31.28 +
   31.29 +int add_unistate(const char *name, StType type)
   31.30 +{
   31.31 +	static const float ident3[] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
   31.32 +	static const float ident4[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
   31.33 +
   31.34 +	if(stateidx.find(name) != stateidx.end()) {
   31.35 +		return stateidx[name];
   31.36 +	}
   31.37 +
   31.38 +	StateItem sitem;
   31.39 +	memset(&sitem, 0, sizeof sitem);
   31.40 +	sitem.type = type;
   31.41 +
   31.42 +	// initialize to a reasonable default value
   31.43 +	switch(type) {
   31.44 +	case ST_MATRIX3:
   31.45 +		memcpy(sitem.fval, ident3, sizeof ident3);
   31.46 +		break;
   31.47 +
   31.48 +	case ST_MATRIX4:
   31.49 +		memcpy(sitem.fval, ident4, sizeof ident4);
   31.50 +		break;
   31.51 +
   31.52 +	default:
   31.53 +		break;	// in all other cases leave it zero (see memset above)
   31.54 +	}
   31.55 +
   31.56 +	int sidx = state.size();
   31.57 +	state.push_back(sitem);
   31.58 +	stateidx[name] = sidx;
   31.59 +
   31.60 +	debug_log("adding uniform state [%d]: %s %s\n", sidx, typestr(sitem.type), name);
   31.61 +
   31.62 +	return sidx;
   31.63 +}
   31.64 +
   31.65 +int get_unistate_index(const char *name)
   31.66 +{
   31.67 +	std::map<std::string, int>::const_iterator it = stateidx.find(name);
   31.68 +	if(it != stateidx.end()) {
   31.69 +		return it->second;
   31.70 +	}
   31.71 +	return -1;
   31.72 +}
   31.73 +
   31.74 +#define CHECK_INDEX(i)	\
   31.75 +	if(i < 0 || i >= (int)state.size()) return
   31.76 +
   31.77 +#define CHECK_COUNT(count, type) \
   31.78 +	do { \
   31.79 +		int max_elem = type_nelem(type); \
   31.80 +		if(!(count) || (count) > max_elem) { \
   31.81 +			count = max_elem; \
   31.82 +		} \
   31.83 +	} while(0)
   31.84 +
   31.85 +void set_unistate(int sidx, const int *val, int count)
   31.86 +{
   31.87 +	CHECK_INDEX(sidx);
   31.88 +	CHECK_COUNT(count, state[sidx].type);
   31.89 +
   31.90 +	memcpy(state[sidx].ival, val, count * sizeof *state[sidx].ival);
   31.91 +}
   31.92 +
   31.93 +void set_unistate(int sidx, const float *val, int count)
   31.94 +{
   31.95 +	CHECK_INDEX(sidx);
   31.96 +	CHECK_COUNT(count, state[sidx].type);
   31.97 +
   31.98 +	memcpy(state[sidx].fval, val, count * sizeof *state[sidx].fval);
   31.99 +	state[sidx].transpose = 0;
  31.100 +}
  31.101 +
  31.102 +void get_unistate(int sidx, int *val, int count)
  31.103 +{
  31.104 +	CHECK_INDEX(sidx);
  31.105 +	CHECK_COUNT(count, state[sidx].type);
  31.106 +
  31.107 +	memcpy(val, state[sidx].ival, count * sizeof *val);
  31.108 +}
  31.109 +
  31.110 +void get_unistate(int sidx, float *val, int count)
  31.111 +{
  31.112 +	CHECK_INDEX(sidx);
  31.113 +	CHECK_COUNT(count, state[sidx].type);
  31.114 +
  31.115 +	memcpy(val, state[sidx].fval, count * sizeof *val);
  31.116 +}
  31.117 +
  31.118 +void set_unistate(int sidx, int val)
  31.119 +{
  31.120 +	set_unistate(sidx, &val, 1);
  31.121 +}
  31.122 +
  31.123 +void set_unistate(int sidx, float val)
  31.124 +{
  31.125 +	set_unistate(sidx, &val, 1);
  31.126 +}
  31.127 +
  31.128 +void set_unistate(int sidx, const Vector2 &vec)
  31.129 +{
  31.130 +	set_unistate(sidx, &vec.x, 2);
  31.131 +}
  31.132 +
  31.133 +void set_unistate(int sidx, const Vector3 &vec)
  31.134 +{
  31.135 +	set_unistate(sidx, &vec.x, 3);
  31.136 +}
  31.137 +
  31.138 +void set_unistate(int sidx, const Vector4 &vec)
  31.139 +{
  31.140 +	set_unistate(sidx, &vec.x, 4);
  31.141 +}
  31.142 +
  31.143 +void set_unistate(int sidx, const Matrix3x3 &mat)
  31.144 +{
  31.145 +	set_unistate(sidx, mat[0], 9);
  31.146 +	state[sidx].transpose = 1;
  31.147 +}
  31.148 +
  31.149 +void set_unistate(int sidx, const Matrix4x4 &mat)
  31.150 +{
  31.151 +	set_unistate(sidx, mat[0], 16);
  31.152 +	state[sidx].transpose = 1;
  31.153 +}
  31.154 +
  31.155 +
  31.156 +int set_unistate(const char *name, int *val, int count)
  31.157 +{
  31.158 +	int sidx = get_unistate_index(name);
  31.159 +	if(sidx < 0) {
  31.160 +		StType type = int_type(count);
  31.161 +		if(type == ST_UNKNOWN) {
  31.162 +			error_log("invalid element count (%d) while setting previously unknown unistate item \"%s\"\n",
  31.163 +					count, name);
  31.164 +			return -1;
  31.165 +		}
  31.166 +
  31.167 +		sidx = add_unistate(name, type);
  31.168 +	}
  31.169 +	set_unistate(sidx, val);
  31.170 +	return sidx;
  31.171 +}
  31.172 +
  31.173 +int set_unistate(const char *name, float *val, int count)
  31.174 +{
  31.175 +	int sidx = get_unistate_index(name);
  31.176 +	if(sidx < 0) {
  31.177 +		StType type = float_type(count);
  31.178 +		if(type == ST_UNKNOWN) {
  31.179 +			error_log("invalid element count (%d) while setting previously unknown unistate item \"%s\"\n",
  31.180 +					count, name);
  31.181 +			return -1;
  31.182 +		}
  31.183 +
  31.184 +		sidx = add_unistate(name, type);
  31.185 +	}
  31.186 +	set_unistate(sidx, val);
  31.187 +	return sidx;
  31.188 +}
  31.189 +
  31.190 +int set_unistate(const char *name, int val)
  31.191 +{
  31.192 +	int sidx = get_unistate_index(name);
  31.193 +	if(sidx < 0) {
  31.194 +		sidx = add_unistate(name, ST_INT);
  31.195 +	}
  31.196 +	set_unistate(sidx, val);
  31.197 +	return sidx;
  31.198 +}
  31.199 +
  31.200 +int set_unistate(const char *name, float val)
  31.201 +{
  31.202 +	int sidx = get_unistate_index(name);
  31.203 +	if(sidx < 0) {
  31.204 +		sidx = add_unistate(name, ST_FLOAT);
  31.205 +	}
  31.206 +	set_unistate(sidx, val);
  31.207 +	return sidx;
  31.208 +}
  31.209 +
  31.210 +int set_unistate(const char *name, const Vector2 &vec)
  31.211 +{
  31.212 +	int sidx = get_unistate_index(name);
  31.213 +	if(sidx < 0) {
  31.214 +		sidx = add_unistate(name, ST_FLOAT2);
  31.215 +	}
  31.216 +	set_unistate(sidx, vec);
  31.217 +	return sidx;
  31.218 +}
  31.219 +
  31.220 +int set_unistate(const char *name, const Vector3 &vec)
  31.221 +{
  31.222 +	int sidx = get_unistate_index(name);
  31.223 +	if(sidx < 0) {
  31.224 +		sidx = add_unistate(name, ST_FLOAT3);
  31.225 +	}
  31.226 +	set_unistate(sidx, vec);
  31.227 +	return sidx;
  31.228 +}
  31.229 +
  31.230 +int set_unistate(const char *name, const Vector4 &vec)
  31.231 +{
  31.232 +	int sidx = get_unistate_index(name);
  31.233 +	if(sidx < 0) {
  31.234 +		sidx = add_unistate(name, ST_FLOAT4);
  31.235 +	}
  31.236 +	set_unistate(sidx, vec);
  31.237 +	return sidx;
  31.238 +}
  31.239 +
  31.240 +int set_unistate(const char *name, const Matrix3x3 &mat)
  31.241 +{
  31.242 +	int sidx = get_unistate_index(name);
  31.243 +	if(sidx < 0) {
  31.244 +		sidx = add_unistate(name, ST_MATRIX3);
  31.245 +	}
  31.246 +	set_unistate(sidx, mat);
  31.247 +	return sidx;
  31.248 +}
  31.249 +
  31.250 +int set_unistate(const char *name, const Matrix4x4 &mat)
  31.251 +{
  31.252 +	int sidx = get_unistate_index(name);
  31.253 +	if(sidx < 0) {
  31.254 +		sidx = add_unistate(name, ST_MATRIX4);
  31.255 +	}
  31.256 +	set_unistate(sidx, mat);
  31.257 +	return sidx;
  31.258 +}
  31.259 +
  31.260 +
  31.261 +int get_unistate_int(int sidx)
  31.262 +{
  31.263 +	int val = 0;
  31.264 +	get_unistate(sidx, &val, 1);
  31.265 +	return val;
  31.266 +}
  31.267 +
  31.268 +float get_unistate_float(int sidx)
  31.269 +{
  31.270 +	float val = 0.0f;
  31.271 +	get_unistate(sidx, &val, 1);
  31.272 +	return val;
  31.273 +}
  31.274 +
  31.275 +Vector2 get_unistate_vec2(int sidx)
  31.276 +{
  31.277 +	float val[2] = {0.0f, 0.0f};
  31.278 +	get_unistate(sidx, val, 2);
  31.279 +	return Vector2(val[0], val[1]);
  31.280 +}
  31.281 +
  31.282 +Vector3 get_unistate_vec3(int sidx)
  31.283 +{
  31.284 +	float val[3] = {0.0f, 0.0f, 0.0f};
  31.285 +	get_unistate(sidx, val, 3);
  31.286 +	return Vector3(val[0], val[1], val[2]);
  31.287 +}
  31.288 +
  31.289 +Vector4 get_unistate_vec4(int sidx)
  31.290 +{
  31.291 +	float val[4] = {0.0f, 0.0f, 0.0f};
  31.292 +	get_unistate(sidx, val, 4);
  31.293 +	return Vector4(val[0], val[1], val[2], val[3]);
  31.294 +}
  31.295 +
  31.296 +Matrix3x3 get_unistate_mat3(int sidx)
  31.297 +{
  31.298 +	Matrix3x3 res;
  31.299 +	get_unistate(sidx, res.m[0], 9);
  31.300 +	return res;
  31.301 +}
  31.302 +
  31.303 +Matrix4x4 get_unistate_mat4(int sidx)
  31.304 +{
  31.305 +	Matrix4x4 res;
  31.306 +	get_unistate(sidx, res.m[0], 16);
  31.307 +	return res;
  31.308 +}
  31.309 +
  31.310 +
  31.311 +int get_unistate_int(const char *name)
  31.312 +{
  31.313 +	int sidx = get_unistate_index(name);
  31.314 +	if(sidx == -1) {
  31.315 +		return 0;
  31.316 +	}
  31.317 +	return get_unistate_int(sidx);
  31.318 +}
  31.319 +
  31.320 +float get_unistate_float(const char *name)
  31.321 +{
  31.322 +	int sidx = get_unistate_index(name);
  31.323 +	if(sidx == -1) {
  31.324 +		return 0.0f;
  31.325 +	}
  31.326 +	return get_unistate_float(sidx);
  31.327 +}
  31.328 +
  31.329 +Vector2 get_unistate_vec2(const char *name)
  31.330 +{
  31.331 +	int sidx = get_unistate_index(name);
  31.332 +	if(sidx == -1) {
  31.333 +		return Vector2();
  31.334 +	}
  31.335 +	return get_unistate_vec2(sidx);
  31.336 +}
  31.337 +
  31.338 +Vector3 get_unistate_vec3(const char *name)
  31.339 +{
  31.340 +	int sidx = get_unistate_index(name);
  31.341 +	if(sidx == -1) {
  31.342 +		return Vector3();
  31.343 +	}
  31.344 +	return get_unistate_vec3(sidx);
  31.345 +}
  31.346 +
  31.347 +Vector4 get_unistate_vec4(const char *name)
  31.348 +{
  31.349 +	int sidx = get_unistate_index(name);
  31.350 +	if(sidx == -1) {
  31.351 +		return Vector4();
  31.352 +	}
  31.353 +	return get_unistate_vec4(sidx);
  31.354 +}
  31.355 +
  31.356 +Matrix3x3 get_unistate_mat3(const char *name)
  31.357 +{
  31.358 +	int sidx = get_unistate_index(name);
  31.359 +	if(sidx == -1) {
  31.360 +		return Matrix3x3();
  31.361 +	}
  31.362 +	return get_unistate_mat3(sidx);
  31.363 +}
  31.364 +
  31.365 +Matrix4x4 get_unistate_mat4(const char *name)
  31.366 +{
  31.367 +	int sidx = get_unistate_index(name);
  31.368 +	if(sidx == -1) {
  31.369 +		return Matrix4x4();
  31.370 +	}
  31.371 +	return get_unistate_mat4(sidx);
  31.372 +}
  31.373 +
  31.374 +
  31.375 +void setup_unistate(const ShaderProg *sdr)
  31.376 +{
  31.377 +	if(!sdr) {
  31.378 +		if(!(sdr = ShaderProg::current)) {
  31.379 +			return;
  31.380 +		}
  31.381 +	}
  31.382 +
  31.383 +	sdr->setup_state_uniforms();
  31.384 +}
  31.385 +
  31.386 +bool setup_unistate(int sidx, const ShaderProg *sdr, int loc)
  31.387 +{
  31.388 +	if(loc < 0 || sidx < 0 || sidx >= (int)state.size()) {
  31.389 +		return false;
  31.390 +	}
  31.391 +
  31.392 +	CHECKGLERR;
  31.393 +	glUseProgram(sdr->get_id());
  31.394 +	CHECKGLERR;
  31.395 +
  31.396 +	switch(state[sidx].type) {
  31.397 +	case ST_INT:
  31.398 +		glUniform1iv(loc, 1, state[sidx].ival);
  31.399 +		break;
  31.400 +	case ST_INT2:
  31.401 +		glUniform2iv(loc, 1, state[sidx].ival);
  31.402 +		break;
  31.403 +	case ST_INT3:
  31.404 +		glUniform3iv(loc, 1, state[sidx].ival);
  31.405 +		break;
  31.406 +	case ST_INT4:
  31.407 +		glUniform4iv(loc, 1, state[sidx].ival);
  31.408 +		break;
  31.409 +
  31.410 +	case ST_FLOAT:
  31.411 +		glUniform1fv(loc, 1, state[sidx].fval);
  31.412 +		break;
  31.413 +	case ST_FLOAT2:
  31.414 +		glUniform2fv(loc, 1, state[sidx].fval);
  31.415 +		break;
  31.416 +	case ST_FLOAT3:
  31.417 +		glUniform3fv(loc, 1, state[sidx].fval);
  31.418 +		break;
  31.419 +	case ST_FLOAT4:
  31.420 +		glUniform4fv(loc, 1, state[sidx].fval);
  31.421 +		break;
  31.422 +
  31.423 +	case ST_MATRIX3:
  31.424 +#ifdef GL_ES_VERSION_2_0
  31.425 +		{
  31.426 +			float tmat[9], *ptr = tmat;
  31.427 +			for(int i=0; i<3; i++) {
  31.428 +				for(int j=0; j<3; j++) {
  31.429 +					*ptr++ = state[sidx].fval[j * 3 + i];
  31.430 +				}
  31.431 +			}
  31.432 +			glUniformMatrix3fv(loc, 1, GL_FALSE, tmat);
  31.433 +		}
  31.434 +#else
  31.435 +		glUniformMatrix3fv(loc, 1, state[sidx].transpose, state[sidx].fval);
  31.436 +#endif
  31.437 +		break;
  31.438 +
  31.439 +	case ST_MATRIX4:
  31.440 +#ifdef GL_ES_VERSION_2_0
  31.441 +		{
  31.442 +			float tmat[16], *ptr = tmat;
  31.443 +			for(int i=0; i<4; i++) {
  31.444 +				for(int j=0; j<4; j++) {
  31.445 +					*ptr++ = state[sidx].fval[j * 4 + i];
  31.446 +				}
  31.447 +			}
  31.448 +			glUniformMatrix4fv(loc, 1, GL_FALSE, tmat);
  31.449 +		}
  31.450 +#else
  31.451 +		glUniformMatrix4fv(loc, 1, state[sidx].transpose, state[sidx].fval);
  31.452 +#endif
  31.453 +		break;
  31.454 +
  31.455 +	default:
  31.456 +		return false;
  31.457 +	}
  31.458 +
  31.459 +	CHECKGLERR;
  31.460 +	return true;
  31.461 +}
  31.462 +
  31.463 +bool setup_unistate(const char *name, const ShaderProg *sdr)
  31.464 +{
  31.465 +	int loc = sdr->get_uniform_location(name);
  31.466 +	if(loc == -1) {
  31.467 +		return false;
  31.468 +	}
  31.469 +	return setup_unistate(get_unistate_index(name), sdr, loc);
  31.470 +}
  31.471 +
  31.472 +void set_world_matrix(const Matrix4x4 &mat)
  31.473 +{
  31.474 +	static int sidx = -1, sidx_transp, sidx_mat3;
  31.475 +
  31.476 +	if(sidx == -1) {
  31.477 +		sidx = add_unistate("st_world_matrix", ST_MATRIX4);
  31.478 +		sidx_mat3 = add_unistate("st_world_matrix3", ST_MATRIX3);
  31.479 +		sidx_transp = add_unistate("st_world_matrix_transpose", ST_MATRIX4);
  31.480 +	}
  31.481 +
  31.482 +	set_unistate(sidx, mat);
  31.483 +	set_unistate(sidx_mat3, Matrix3x3(mat));
  31.484 +	set_unistate(sidx_transp, mat[0]);	// by using the float* variant, we unset the transpose flag
  31.485 +}
  31.486 +
  31.487 +void set_view_matrix(const Matrix4x4 &mat)
  31.488 +{
  31.489 +	static int sidx = -1, sidx_transp, sidx_mat3;
  31.490 +
  31.491 +	if(sidx == -1) {
  31.492 +		sidx = add_unistate("st_view_matrix", ST_MATRIX4);
  31.493 +		sidx_mat3 = add_unistate("st_view_matrix3", ST_MATRIX3);
  31.494 +		sidx_transp = add_unistate("st_view_matrix_transpose", ST_MATRIX4);
  31.495 +	}
  31.496 +
  31.497 +	set_unistate(sidx, mat);
  31.498 +	set_unistate(sidx_mat3, Matrix3x3(mat));
  31.499 +	set_unistate(sidx_transp, mat[0]);	// by using the float* variant, we unset the transpose flag
  31.500 +}
  31.501 +
  31.502 +void set_projection_matrix(const Matrix4x4 &mat)
  31.503 +{
  31.504 +	static int sidx = -1;
  31.505 +
  31.506 +	if(sidx == -1) {
  31.507 +		sidx = add_unistate("st_proj_matrix", ST_MATRIX4);
  31.508 +	}
  31.509 +
  31.510 +	set_unistate(sidx, mat);
  31.511 +}
  31.512 +
  31.513 +void set_texture_matrix(const Matrix4x4 &mat)
  31.514 +{
  31.515 +	static int sidx = -1;
  31.516 +
  31.517 +	if(sidx == -1) {
  31.518 +		sidx = add_unistate("st_tex_matrix", ST_MATRIX4);
  31.519 +	}
  31.520 +
  31.521 +	set_unistate(sidx, mat);
  31.522 +}
  31.523 +
  31.524 +Matrix4x4 get_world_matrix()
  31.525 +{
  31.526 +	static int sidx = -1;
  31.527 +
  31.528 +	if(sidx == -1) {
  31.529 +		if((sidx = get_unistate_index("st_world_matrix")) == -1) {
  31.530 +			return Matrix4x4();
  31.531 +		}
  31.532 +	}
  31.533 +	return get_unistate_mat4(sidx);
  31.534 +}
  31.535 +
  31.536 +Matrix4x4 get_view_matrix()
  31.537 +{
  31.538 +	static int sidx = -1;
  31.539 +
  31.540 +	if(sidx == -1) {
  31.541 +		if((sidx = get_unistate_index("st_view_matrix")) == -1) {
  31.542 +			return Matrix4x4();
  31.543 +		}
  31.544 +	}
  31.545 +	return get_unistate_mat4(sidx);
  31.546 +}
  31.547 +
  31.548 +Matrix4x4 get_projection_matrix()
  31.549 +{
  31.550 +	static int sidx = -1;
  31.551 +
  31.552 +	if(sidx == -1) {
  31.553 +		if((sidx = get_unistate_index("st_proj_matrix")) == -1) {
  31.554 +			return Matrix4x4();
  31.555 +		}
  31.556 +	}
  31.557 +	return get_unistate_mat4(sidx);
  31.558 +}
  31.559 +
  31.560 +Matrix4x4 get_texture_matrix()
  31.561 +{
  31.562 +	static int sidx = -1;
  31.563 +
  31.564 +	if(sidx == -1) {
  31.565 +		if((sidx = get_unistate_index("st_tex_matrix")) == -1) {
  31.566 +			return Matrix4x4();
  31.567 +		}
  31.568 +	}
  31.569 +	return get_unistate_mat4(sidx);
  31.570 +}
  31.571 +
  31.572 +void setup_gl_matrices()
  31.573 +{
  31.574 +#ifdef USE_OLDGL
  31.575 +	Matrix4x4 modelview = get_world_matrix() * get_view_matrix();
  31.576 +	Matrix4x4 proj = get_projection_matrix();
  31.577 +	Matrix4x4 tex = get_texture_matrix();
  31.578 +
  31.579 +	glMatrixMode(GL_TEXTURE);
  31.580 +	glLoadTransposeMatrixf(tex[0]);
  31.581 +	glMatrixMode(GL_PROJECTION);
  31.582 +	glLoadTransposeMatrixf(proj[0]);
  31.583 +	glMatrixMode(GL_MODELVIEW);
  31.584 +	glLoadTransposeMatrixf(modelview[0]);
  31.585 +#endif
  31.586 +}
  31.587 +
  31.588 +static const char *typestr(StType type)
  31.589 +{
  31.590 +	switch(type) {
  31.591 +	case ST_INT:
  31.592 +		return "int";
  31.593 +	case ST_INT2:
  31.594 +		return "ivec2";
  31.595 +	case ST_INT3:
  31.596 +		return "ivec3";
  31.597 +	case ST_INT4:
  31.598 +		return "ivec4";
  31.599 +	case ST_FLOAT:
  31.600 +		return "float";
  31.601 +	case ST_FLOAT2:
  31.602 +		return "vec2";
  31.603 +	case ST_FLOAT3:
  31.604 +		return "vec3";
  31.605 +	case ST_FLOAT4:
  31.606 +		return "vec4";
  31.607 +	case ST_MATRIX3:
  31.608 +		return "mat3";
  31.609 +	case ST_MATRIX4:
  31.610 +		return "mat4";
  31.611 +
  31.612 +	default:
  31.613 +		break;
  31.614 +	}
  31.615 +	return "<unknown>";
  31.616 +}
  31.617 +
  31.618 +static int type_nelem(StType type)
  31.619 +{
  31.620 +	switch(type) {
  31.621 +	case ST_INT:
  31.622 +	case ST_FLOAT:
  31.623 +		return 1;
  31.624 +	case ST_INT2:
  31.625 +	case ST_FLOAT2:
  31.626 +		return 2;
  31.627 +	case ST_INT3:
  31.628 +	case ST_FLOAT3:
  31.629 +		return 3;
  31.630 +	case ST_INT4:
  31.631 +	case ST_FLOAT4:
  31.632 +		return 4;
  31.633 +	case ST_MATRIX3:
  31.634 +		return 9;
  31.635 +	case ST_MATRIX4:
  31.636 +		return 16;
  31.637 +
  31.638 +	default:
  31.639 +		break;
  31.640 +	}
  31.641 +
  31.642 +	return 0;
  31.643 +}
  31.644 +
  31.645 +static StType float_type(int elem)
  31.646 +{
  31.647 +	switch(elem) {
  31.648 +	case 1:
  31.649 +		return ST_FLOAT;
  31.650 +	case 2:
  31.651 +		return ST_FLOAT2;
  31.652 +	case 3:
  31.653 +		return ST_FLOAT3;
  31.654 +	case 4:
  31.655 +		return ST_FLOAT4;
  31.656 +	case 9:
  31.657 +		return ST_MATRIX3;
  31.658 +	case 16:
  31.659 +		return ST_MATRIX4;
  31.660 +	default:
  31.661 +		break;
  31.662 +	}
  31.663 +	return ST_UNKNOWN;
  31.664 +}
  31.665 +
  31.666 +static StType int_type(int elem)
  31.667 +{
  31.668 +	switch(elem) {
  31.669 +	case 1:
  31.670 +		return ST_INT;
  31.671 +	case 2:
  31.672 +		return ST_INT2;
  31.673 +	case 3:
  31.674 +		return ST_INT3;
  31.675 +	case 4:
  31.676 +		return ST_INT4;
  31.677 +	default:
  31.678 +		break;
  31.679 +	}
  31.680 +	return ST_UNKNOWN;
  31.681 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/src/unistate.h	Sun Aug 24 09:41:24 2014 +0300
    32.3 @@ -0,0 +1,104 @@
    32.4 +#ifndef UNISTATE_H_
    32.5 +#define UNISTATE_H_
    32.6 +
    32.7 +#include "vmath/vmath.h"
    32.8 +
    32.9 +class ShaderProg;
   32.10 +
   32.11 +enum StType {
   32.12 +	ST_UNKNOWN,
   32.13 +	ST_INT,	ST_INT2, ST_INT3, ST_INT4,
   32.14 +	ST_FLOAT, ST_FLOAT2, ST_FLOAT3, ST_FLOAT4,
   32.15 +	ST_MATRIX3, ST_MATRIX4
   32.16 +};
   32.17 +
   32.18 +int add_unistate(const char *name, StType type);
   32.19 +int get_unistate_index(const char *name);
   32.20 +
   32.21 +/** set the uniform state identified by \param sidx by copying
   32.22 + * a number of elements from \param val. If \param count is 0
   32.23 + * then it's automatically set based on the type of this state item.
   32.24 + * @{ */
   32.25 +void set_unistate(int sidx, const int *val, int count = 0);
   32.26 +void set_unistate(int sidx, const float *val, int count = 0);
   32.27 +/// @}
   32.28 +
   32.29 +/** get the uniform state identified by \param sidx by copying
   32.30 + * a number of elements into \param val. If \param count is 0
   32.31 + * then it's automatically set based on the type of this state item.
   32.32 + * @{ */
   32.33 +void get_unistate(int sidx, int *val, int count = 0);
   32.34 +void get_unistate(int sidx, float *val, int count = 0);
   32.35 +/// @}
   32.36 +
   32.37 +/// convenience versions of set_unistate @{
   32.38 +void set_unistate(int sidx, int val);
   32.39 +void set_unistate(int sidx, float val);
   32.40 +void set_unistate(int sidx, const Vector2 &vec);
   32.41 +void set_unistate(int sidx, const Vector3 &vec);
   32.42 +void set_unistate(int sidx, const Vector4 &vec);
   32.43 +void set_unistate(int sidx, const Matrix3x3 &mat);
   32.44 +void set_unistate(int sidx, const Matrix4x4 &mat);
   32.45 +/// @}
   32.46 +
   32.47 +/** convenience functions for setting the uniform state by name.
   32.48 + * if the name cannot be found in the current set of uniform state
   32.49 + * items, a new one is created with a type derived from the variant
   32.50 + * of the function that was called (which might not be what you want).
   32.51 + * The index of the state item is returned.
   32.52 + * @{ */
   32.53 +int set_unistate(const char *name, int *val, int count = 0);
   32.54 +int set_unistate(const char *name, float *val, int count = 0);
   32.55 +int set_unistate(const char *name, int val);
   32.56 +int set_unistate(const char *name, float val);
   32.57 +int set_unistate(const char *name, const Vector2 &vec);
   32.58 +int set_unistate(const char *name, const Vector3 &vec);
   32.59 +int set_unistate(const char *name, const Vector4 &vec);
   32.60 +int set_unistate(const char *name, const Matrix3x3 &mat);
   32.61 +int set_unistate(const char *name, const Matrix4x4 &mat);
   32.62 +/// @}
   32.63 +
   32.64 +/// convenience versions of get_unistate @{
   32.65 +int get_unistate_int(int sidx);
   32.66 +float get_unistate_float(int sidx);
   32.67 +Vector2 get_unistate_vec2(int sidx);
   32.68 +Vector3 get_unistate_vec3(int sidx);
   32.69 +Vector4 get_unistate_vec4(int sidx);
   32.70 +Matrix3x3 get_unistate_mat3(int sidx);
   32.71 +Matrix4x4 get_unistate_mat4(int sidx);
   32.72 +/// @}
   32.73 +
   32.74 +/// convenience versions of get_unistate for getting the uniform state by name @{
   32.75 +int get_unistate_int(const char *name);
   32.76 +float get_unistate_float(const char *name);
   32.77 +Vector2 get_unistate_vec2(const char *name);
   32.78 +Vector3 get_unistate_vec3(const char *name);
   32.79 +Vector4 get_unistate_vec4(const char *name);
   32.80 +Matrix3x3 get_unistate_mat3(const char *name);
   32.81 +Matrix4x4 get_unistate_mat4(const char *name);
   32.82 +/// @}
   32.83 +
   32.84 +/** Prepare for rendering by setting up all the state uniforms in the shader sdr.
   32.85 + * If sdr is null, then use the "current" shader as per ShaderProg::current
   32.86 + */
   32.87 +void setup_unistate(const ShaderProg *sdr = 0);
   32.88 +
   32.89 +bool setup_unistate(int sidx, const ShaderProg *sdr, int loc);
   32.90 +bool setup_unistate(const char *name, const ShaderProg *sdr);
   32.91 +
   32.92 +// special functions for setting the rendering pipeline matrices
   32.93 +void set_world_matrix(const Matrix4x4 &mat);
   32.94 +void set_view_matrix(const Matrix4x4 &mat);
   32.95 +void set_projection_matrix(const Matrix4x4 &mat);
   32.96 +void set_texture_matrix(const Matrix4x4 &mat);
   32.97 +
   32.98 +Matrix4x4 get_world_matrix();
   32.99 +Matrix4x4 get_view_matrix();
  32.100 +Matrix4x4 get_projection_matrix();
  32.101 +Matrix4x4 get_texture_matrix();
  32.102 +
  32.103 +void setup_gl_matrices();	// this shouldn't be needed in the final code
  32.104 +
  32.105 +// TODO should do a matrix stack at some point ...
  32.106 +
  32.107 +#endif	// UNISTATE_H_
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/src/xform_node.cc	Sun Aug 24 09:41:24 2014 +0300
    33.3 @@ -0,0 +1,461 @@
    33.4 +#include <assert.h>
    33.5 +#include <algorithm>
    33.6 +#include "xform_node.h"
    33.7 +#include "anim/anim.h"
    33.8 +#include "anim/track.h"
    33.9 +
   33.10 +static inline anm_interpolator track_interpolator(Interp in);
   33.11 +static inline anm_extrapolator track_extrapolator(Extrap ex);
   33.12 +
   33.13 +XFormNode::XFormNode()
   33.14 +{
   33.15 +	anm = new anm_node;
   33.16 +	anm_init_node(anm);
   33.17 +	parent = 0;
   33.18 +
   33.19 +	// TODO read them from anm to get the correct initial values
   33.20 +	interp = INTERP_LINEAR;
   33.21 +	extrap = EXTRAP_EXTEND;
   33.22 +}
   33.23 +
   33.24 +XFormNode::~XFormNode()
   33.25 +{
   33.26 +	anm_destroy_node(anm);
   33.27 +	delete anm;
   33.28 +}
   33.29 +
   33.30 +void XFormNode::set_name(const char *name)
   33.31 +{
   33.32 +	anm_set_node_name(anm, name);
   33.33 +}
   33.34 +
   33.35 +const char *XFormNode::get_name() const
   33.36 +{
   33.37 +	return anm_get_node_name(anm);
   33.38 +}
   33.39 +
   33.40 +void XFormNode::set_interpolator(Interp in)
   33.41 +{
   33.42 +	anm_set_interpolator(anm, track_interpolator(in));
   33.43 +	interp = in;
   33.44 +}
   33.45 +
   33.46 +Interp XFormNode::get_interpolator() const
   33.47 +{
   33.48 +	return interp;
   33.49 +}
   33.50 +
   33.51 +void XFormNode::set_extrapolator(Extrap ex)
   33.52 +{
   33.53 +	anm_set_extrapolator(anm, track_extrapolator(ex));
   33.54 +	extrap = ex;
   33.55 +}
   33.56 +
   33.57 +Extrap XFormNode::get_extrapolator() const
   33.58 +{
   33.59 +	return extrap;
   33.60 +}
   33.61 +
   33.62 +XFormNode *XFormNode::get_parent()
   33.63 +{
   33.64 +	return parent;
   33.65 +}
   33.66 +
   33.67 +const XFormNode *XFormNode::get_parent() const
   33.68 +{
   33.69 +	return parent;
   33.70 +}
   33.71 +
   33.72 +void XFormNode::add_child(XFormNode *child)
   33.73 +{
   33.74 +	children.push_back(child);
   33.75 +	anm_link_node(anm, child->anm);
   33.76 +	child->parent = this;
   33.77 +}
   33.78 +
   33.79 +void XFormNode::remove_child(XFormNode *child)
   33.80 +{
   33.81 +	std::vector<XFormNode*>::iterator it;
   33.82 +	it = std::find(children.begin(), children.end(), child);
   33.83 +	if(it != children.end()) {
   33.84 +		children.erase(it);
   33.85 +		anm_unlink_node(anm, child->anm);
   33.86 +
   33.87 +		if(child->parent == this) {
   33.88 +			child->parent = 0;
   33.89 +		}
   33.90 +	}
   33.91 +}
   33.92 +
   33.93 +int XFormNode::get_children_count() const
   33.94 +{
   33.95 +	return (int)children.size();
   33.96 +}
   33.97 +
   33.98 +XFormNode *XFormNode::get_child(int idx)
   33.99 +{
  33.100 +	if(idx >= 0 && idx < get_children_count()) {
  33.101 +		return children[idx];
  33.102 +	}
  33.103 +	return 0;
  33.104 +}
  33.105 +
  33.106 +const XFormNode *XFormNode::get_child(int idx) const
  33.107 +{
  33.108 +	if(idx >= 0 && idx < get_children_count()) {
  33.109 +		return children[idx];
  33.110 +	}
  33.111 +	return 0;
  33.112 +}
  33.113 +
  33.114 +
  33.115 +void XFormNode::use_animation(int idx)
  33.116 +{
  33.117 +	if(idx >= 0) {
  33.118 +		anm_use_animation(anm, idx);
  33.119 +	}
  33.120 +}
  33.121 +
  33.122 +void XFormNode::use_animation(const char *name)
  33.123 +{
  33.124 +	anm_use_animation(anm, anm_find_animation(anm, name));
  33.125 +}
  33.126 +
  33.127 +void XFormNode::use_animation(int aidx, int bidx, float t)
  33.128 +{
  33.129 +	anm_use_animations(anm, aidx, bidx, t);
  33.130 +}
  33.131 +
  33.132 +void XFormNode::use_animation(const char *aname, const char *bname, float t)
  33.133 +{
  33.134 +	int aidx = anm_find_animation(anm, aname);
  33.135 +	int bidx = anm_find_animation(anm, bname);
  33.136 +
  33.137 +	if(aidx == -1) {
  33.138 +		use_animation(bidx);
  33.139 +	}
  33.140 +	if(bidx == -1) {
  33.141 +		use_animation(aidx);
  33.142 +	}
  33.143 +	anm_use_animations(anm, aidx, bidx, t);
  33.144 +}
  33.145 +
  33.146 +int XFormNode::get_active_animation_index(int which) const
  33.147 +{
  33.148 +	return anm_get_active_animation_index(anm, which);
  33.149 +}
  33.150 +
  33.151 +float XFormNode::get_active_animation_mix() const
  33.152 +{
  33.153 +	return anm_get_active_animation_mix(anm);
  33.154 +}
  33.155 +
  33.156 +int XFormNode::get_animation_count() const
  33.157 +{
  33.158 +	return anm_get_animation_count(anm);
  33.159 +}
  33.160 +
  33.161 +void XFormNode::add_animation(const char *name)
  33.162 +{
  33.163 +	int idx = get_animation_count();
  33.164 +
  33.165 +	anm_add_animation(anm);
  33.166 +	use_animation(idx);
  33.167 +
  33.168 +	if(name) {
  33.169 +		set_animation_name(name);
  33.170 +	}
  33.171 +}
  33.172 +
  33.173 +void XFormNode::set_animation_name(const char *name)
  33.174 +{
  33.175 +	anm_set_active_animation_name(anm, name);
  33.176 +}
  33.177 +
  33.178 +const char *XFormNode::get_animation_name() const
  33.179 +{
  33.180 +	return anm_get_active_animation_name(anm);
  33.181 +}
  33.182 +
  33.183 +
  33.184 +
  33.185 +void XFormNode::set_position(const Vector3 &pos, long tmsec)
  33.186 +{
  33.187 +	anm_set_position(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec));
  33.188 +}
  33.189 +
  33.190 +Vector3 XFormNode::get_node_position(long tmsec) const
  33.191 +{
  33.192 +	vec3_t p = anm_get_node_position(anm, ANM_MSEC2TM(tmsec));
  33.193 +	return Vector3(p.x, p.y, p.z);
  33.194 +}
  33.195 +
  33.196 +void XFormNode::set_rotation(const Quaternion &quat, long tmsec)
  33.197 +{
  33.198 +	anm_set_rotation(anm, quat_cons(quat.s, quat.v.x, quat.v.y, quat.v.z), ANM_MSEC2TM(tmsec));
  33.199 +}
  33.200 +
  33.201 +Quaternion XFormNode::get_node_rotation(long tmsec) const
  33.202 +{
  33.203 +	quat_t q = anm_get_node_rotation(anm, ANM_MSEC2TM(tmsec));
  33.204 +	return Quaternion(q.w, q.x, q.y, q.z);
  33.205 +}
  33.206 +
  33.207 +void XFormNode::set_scaling(const Vector3 &pos, long tmsec)
  33.208 +{
  33.209 +	anm_set_scaling(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec));
  33.210 +}
  33.211 +
  33.212 +Vector3 XFormNode::get_node_scaling(long tmsec) const
  33.213 +{
  33.214 +	vec3_t s = anm_get_node_scaling(anm, ANM_MSEC2TM(tmsec));
  33.215 +	return Vector3(s.x, s.y, s.z);
  33.216 +}
  33.217 +
  33.218 +// these take hierarchy into account
  33.219 +Vector3 XFormNode::get_position(long tmsec) const
  33.220 +{
  33.221 +	vec3_t v = anm_get_position(anm, ANM_MSEC2TM(tmsec));
  33.222 +	return Vector3(v.x, v.y, v.z);
  33.223 +}
  33.224 +
  33.225 +Quaternion XFormNode::get_rotation(long tmsec) const
  33.226 +{
  33.227 +	quat_t q = anm_get_rotation(anm, tmsec);
  33.228 +	return Quaternion(q.w, q.x, q.y, q.z);
  33.229 +}
  33.230 +
  33.231 +Vector3 XFormNode::get_scaling(long tmsec) const
  33.232 +{
  33.233 +	vec3_t v = anm_get_scaling(anm, ANM_MSEC2TM(tmsec));
  33.234 +	return Vector3(v.x, v.y, v.z);
  33.235 +}
  33.236 +
  33.237 +void XFormNode::set_pivot(const Vector3 &pivot)
  33.238 +{
  33.239 +	anm_set_pivot(anm, v3_cons(pivot.x, pivot.y, pivot.z));
  33.240 +}
  33.241 +
  33.242 +Vector3 XFormNode::get_pivot() const
  33.243 +{
  33.244 +	vec3_t p = anm_get_pivot(anm);
  33.245 +	return Vector3(p.x, p.y, p.z);
  33.246 +}
  33.247 +
  33.248 +void XFormNode::set_local_matrix(const Matrix4x4 &mat)
  33.249 +{
  33.250 +	local_matrix = mat;
  33.251 +}
  33.252 +
  33.253 +const Matrix4x4 &XFormNode::get_local_matrix() const
  33.254 +{
  33.255 +	return local_matrix;
  33.256 +}
  33.257 +
  33.258 +void XFormNode::set_bone_matrix(const Matrix4x4 &bmat)
  33.259 +{
  33.260 +	bone_matrix = bmat;
  33.261 +}
  33.262 +
  33.263 +const Matrix4x4 &XFormNode::get_bone_matrix() const
  33.264 +{
  33.265 +	return bone_matrix;
  33.266 +}
  33.267 +
  33.268 +#define FOO
  33.269 +
  33.270 +void XFormNode::get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const
  33.271 +{
  33.272 +	anm_time_t tm = ANM_MSEC2TM(tmsec);
  33.273 +
  33.274 +	if(mat) {
  33.275 +		anm_get_node_matrix(anm, (scalar_t(*)[4])mat, tm);
  33.276 +#ifdef FOO
  33.277 +		*mat = local_matrix * *mat;
  33.278 +#else
  33.279 +		*mat = *mat * local_matrix;
  33.280 +#endif
  33.281 +	}
  33.282 +	if(inv_mat) {
  33.283 +		anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm);
  33.284 +	}
  33.285 +}
  33.286 +
  33.287 +void XFormNode::get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const
  33.288 +{
  33.289 +	anm_time_t tm = ANM_MSEC2TM(tmsec);
  33.290 +
  33.291 +	if(mat) {
  33.292 +		anm_get_matrix(anm, (scalar_t(*)[4])mat, tm);
  33.293 +#ifdef FOO
  33.294 +		*mat = local_matrix * *mat;
  33.295 +#else
  33.296 +		*mat = *mat * local_matrix;
  33.297 +#endif
  33.298 +	}
  33.299 +	if(inv_mat) {
  33.300 +		anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm);
  33.301 +	}
  33.302 +}
  33.303 +
  33.304 +
  33.305 +// ---- Track ----
  33.306 +
  33.307 +Track::Track()
  33.308 +{
  33.309 +	trk = new anm_track;
  33.310 +	anm_init_track(trk);
  33.311 +}
  33.312 +
  33.313 +Track::~Track()
  33.314 +{
  33.315 +	anm_destroy_track(trk);
  33.316 +	delete trk;
  33.317 +}
  33.318 +
  33.319 +Track::Track(const Track &rhs)
  33.320 +{
  33.321 +	trk = new anm_track;
  33.322 +	anm_init_track(trk);
  33.323 +	anm_copy_track(trk, rhs.trk);
  33.324 +	interp = rhs.interp;
  33.325 +	extrap = rhs.extrap;
  33.326 +}
  33.327 +
  33.328 +Track &Track::operator =(const Track &rhs)
  33.329 +{
  33.330 +	if(&rhs == this) {
  33.331 +		return *this;
  33.332 +	}
  33.333 +
  33.334 +	anm_copy_track(trk, rhs.trk);
  33.335 +	interp = rhs.interp;
  33.336 +	extrap = rhs.extrap;
  33.337 +	return *this;
  33.338 +}
  33.339 +
  33.340 +
  33.341 +void Track::set_interpolator(Interp in)
  33.342 +{
  33.343 +	anm_set_track_interpolator(trk, track_interpolator(in));
  33.344 +	interp = in;
  33.345 +}
  33.346 +
  33.347 +Interp Track::get_interpolator() const
  33.348 +{
  33.349 +	return interp;
  33.350 +}
  33.351 +
  33.352 +void Track::set_extrapolator(Extrap ex)
  33.353 +{
  33.354 +	anm_set_track_extrapolator(trk, track_extrapolator(ex));
  33.355 +	extrap = ex;
  33.356 +}
  33.357 +
  33.358 +Extrap Track::get_extrapolator() const
  33.359 +{
  33.360 +	return extrap;
  33.361 +}
  33.362 +
  33.363 +void Track::set_default(double def)
  33.364 +{
  33.365 +	anm_set_track_default(trk, def);
  33.366 +}
  33.367 +
  33.368 +void Track::set_value(float val, long tmsec)
  33.369 +{
  33.370 +	anm_set_value(trk, ANM_MSEC2TM(tmsec), val);
  33.371 +}
  33.372 +
  33.373 +float Track::get_value(long tmsec) const
  33.374 +{
  33.375 +	return anm_get_value(trk, ANM_MSEC2TM(tmsec));
  33.376 +}
  33.377 +
  33.378 +float Track::operator ()(long tmsec) const
  33.379 +{
  33.380 +	return anm_get_value(trk, ANM_MSEC2TM(tmsec));
  33.381 +}
  33.382 +
  33.383 +
  33.384 +// ---- Track3 ----
  33.385 +
  33.386 +void Track3::set_interpolator(Interp in)
  33.387 +{
  33.388 +	for(int i=0; i<3; i++) {
  33.389 +		track[i].set_interpolator(in);
  33.390 +	}
  33.391 +}
  33.392 +
  33.393 +Interp Track3::get_interpolator() const
  33.394 +{
  33.395 +	return track[0].get_interpolator();
  33.396 +}
  33.397 +
  33.398 +void Track3::set_extrapolator(Extrap ex)
  33.399 +{
  33.400 +	for(int i=0; i<3; i++) {
  33.401 +		track[i].set_extrapolator(ex);
  33.402 +	}
  33.403 +}
  33.404 +
  33.405 +Extrap Track3::get_extrapolator() const
  33.406 +{
  33.407 +	return track[0].get_extrapolator();
  33.408 +}
  33.409 +
  33.410 +void Track3::set_default(const Vector3 &def)
  33.411 +{
  33.412 +	for(int i=0; i<3; i++) {
  33.413 +		track[i].set_default(def[i]);
  33.414 +	}
  33.415 +}
  33.416 +
  33.417 +void Track3::set_value(const Vector3 &val, long tmsec)
  33.418 +{
  33.419 +	for(int i=0; i<3; i++) {
  33.420 +		track[i].set_value(val[i], tmsec);
  33.421 +	}
  33.422 +}
  33.423 +
  33.424 +Vector3 Track3::get_value(long tmsec) const
  33.425 +{
  33.426 +	return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec));
  33.427 +}
  33.428 +
  33.429 +Vector3 Track3::operator ()(long tmsec) const
  33.430 +{
  33.431 +	return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec));
  33.432 +}
  33.433 +
  33.434 +
  33.435 +static inline anm_interpolator track_interpolator(Interp in)
  33.436 +{
  33.437 +	switch(in) {
  33.438 +	case INTERP_STEP:
  33.439 +		return ANM_INTERP_STEP;
  33.440 +	case INTERP_LINEAR:
  33.441 +		return ANM_INTERP_LINEAR;
  33.442 +	case INTERP_CUBIC:
  33.443 +		return ANM_INTERP_CUBIC;
  33.444 +	}
  33.445 +
  33.446 +	assert(0);
  33.447 +	return ANM_INTERP_STEP;
  33.448 +}
  33.449 +
  33.450 +static inline anm_extrapolator track_extrapolator(Extrap ex)
  33.451 +{
  33.452 +	switch(ex) {
  33.453 +	case EXTRAP_EXTEND:
  33.454 +		return ANM_EXTRAP_EXTEND;
  33.455 +	case EXTRAP_CLAMP:
  33.456 +		return ANM_EXTRAP_CLAMP;
  33.457 +	case EXTRAP_REPEAT:
  33.458 +		return ANM_EXTRAP_REPEAT;
  33.459 +	}
  33.460 +
  33.461 +	assert(0);
  33.462 +	return ANM_EXTRAP_EXTEND;
  33.463 +}
  33.464 +
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/src/xform_node.h	Sun Aug 24 09:41:24 2014 +0300
    34.3 @@ -0,0 +1,154 @@
    34.4 +#ifndef GOATGFX_XFORM_NODE_H_
    34.5 +#define GOATGFX_XFORM_NODE_H_
    34.6 +
    34.7 +#include <vector>
    34.8 +#include "vmath/vector.h"
    34.9 +#include "vmath/quat.h"
   34.10 +#include "vmath/matrix.h"
   34.11 +
   34.12 +
   34.13 +struct anm_node;
   34.14 +struct anm_track;
   34.15 +
   34.16 +enum Interp { INTERP_STEP, INTERP_LINEAR, INTERP_CUBIC };
   34.17 +enum Extrap { EXTRAP_EXTEND, EXTRAP_CLAMP, EXTRAP_REPEAT };
   34.18 +
   34.19 +// NOTE: all time arguments are milliseconds
   34.20 +
   34.21 +class XFormNode {
   34.22 +private:
   34.23 +	struct anm_node *anm;
   34.24 +	std::vector<XFormNode*> children;
   34.25 +	XFormNode *parent;
   34.26 +
   34.27 +	Interp interp;
   34.28 +	Extrap extrap;
   34.29 +
   34.30 +	Matrix4x4 local_matrix;
   34.31 +	Matrix4x4 bone_matrix;
   34.32 +
   34.33 +	XFormNode(const XFormNode &node) {}
   34.34 +	XFormNode &operator =(const XFormNode &node) { return *this; }
   34.35 +
   34.36 +public:
   34.37 +	XFormNode();
   34.38 +	virtual ~XFormNode();
   34.39 +
   34.40 +	virtual void set_name(const char *name);
   34.41 +	virtual const char *get_name() const;
   34.42 +
   34.43 +	virtual void set_interpolator(Interp in);
   34.44 +	virtual Interp get_interpolator() const;
   34.45 +	virtual void set_extrapolator(Extrap ex);
   34.46 +	virtual Extrap get_extrapolator() const;
   34.47 +
   34.48 +	virtual XFormNode *get_parent();
   34.49 +	virtual const XFormNode *get_parent() const;
   34.50 +
   34.51 +	// children management
   34.52 +	virtual void add_child(XFormNode *child);
   34.53 +	virtual void remove_child(XFormNode *child);
   34.54 +
   34.55 +	virtual int get_children_count() const;
   34.56 +	virtual XFormNode *get_child(int idx);
   34.57 +	virtual const XFormNode *get_child(int idx) const;
   34.58 +
   34.59 +
   34.60 +	virtual void use_animation(int idx);
   34.61 +	virtual void use_animation(const char *name);
   34.62 +	virtual void use_animation(int aidx, int bidx, float t);
   34.63 +	virtual void use_animation(const char *aname, const char *bname, float t);
   34.64 +
   34.65 +	virtual int get_active_animation_index(int which = 0) const;
   34.66 +	virtual float get_active_animation_mix() const;
   34.67 +
   34.68 +	virtual int get_animation_count() const;
   34.69 +
   34.70 +	// add a new empty animation slot (recursive)
   34.71 +	virtual void add_animation(const char *name = 0);
   34.72 +
   34.73 +	// set/get the current animation name (set is recursive)
   34.74 +	virtual void set_animation_name(const char *name);
   34.75 +	virtual const char *get_animation_name() const;
   34.76 +
   34.77 +
   34.78 +	virtual void set_position(const Vector3 &pos, long tmsec = 0);
   34.79 +	virtual Vector3 get_node_position(long tmsec = 0) const;
   34.80 +
   34.81 +	virtual void set_rotation(const Quaternion &quat, long tmsec = 0);
   34.82 +	virtual Quaternion get_node_rotation(long tmsec = 0) const;
   34.83 +
   34.84 +	virtual void set_scaling(const Vector3 &pos, long tmsec = 0);
   34.85 +	virtual Vector3 get_node_scaling(long tmsec = 0) const;
   34.86 +
   34.87 +	// these take hierarchy into account
   34.88 +	virtual Vector3 get_position(long tmsec = 0) const;
   34.89 +	virtual Quaternion get_rotation(long tmsec = 0) const;
   34.90 +	virtual Vector3 get_scaling(long tmsec = 0) const;
   34.91 +
   34.92 +	virtual void set_pivot(const Vector3 &pivot);
   34.93 +	virtual Vector3 get_pivot() const;
   34.94 +
   34.95 +	// the local matrix is concatenated with the regular node/anim matrix
   34.96 +	virtual void set_local_matrix(const Matrix4x4 &mat);
   34.97 +	virtual const Matrix4x4 &get_local_matrix() const;
   34.98 +
   34.99 +	// for bone nodes, the transformation of the bone in bind position
  34.100 +	virtual void set_bone_matrix(const Matrix4x4 &bmat);
  34.101 +	virtual const Matrix4x4 &get_bone_matrix() const;
  34.102 +
  34.103 +	// node transformation alone
  34.104 +	virtual void get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const;
  34.105 +
  34.106 +	// node transformation taking hierarchy into account
  34.107 +	virtual void get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const;
  34.108 +};
  34.109 +
  34.110 +
  34.111 +class Track {
  34.112 +private:
  34.113 +	struct anm_track *trk;
  34.114 +	Interp interp;
  34.115 +	Extrap extrap;
  34.116 +
  34.117 +public:
  34.118 +	Track();
  34.119 +	~Track();
  34.120 +
  34.121 +	Track(const Track &trk);
  34.122 +	Track &operator =(const Track &trk);
  34.123 +
  34.124 +	void set_interpolator(Interp in);
  34.125 +	Interp get_interpolator() const;
  34.126 +	void set_extrapolator(Extrap ex);
  34.127 +	Extrap get_extrapolator() const;
  34.128 +
  34.129 +	void set_default(double def);
  34.130 +
  34.131 +	void set_value(float val, long tmsec = 0);
  34.132 +	float get_value(long tmsec = 0) const;
  34.133 +
  34.134 +	// the same as get_value
  34.135 +	float operator ()(long tmsec = 0) const;
  34.136 +};
  34.137 +
  34.138 +class Track3 {
  34.139 +private:
  34.140 +	Track track[3];
  34.141 +
  34.142 +public:
  34.143 +	void set_interpolator(Interp in);
  34.144 +	Interp get_interpolator() const;
  34.145 +	void set_extrapolator(Extrap ex);
  34.146 +	Extrap get_extrapolator() const;
  34.147 +
  34.148 +	void set_default(const Vector3 &def);
  34.149 +
  34.150 +	void set_value(const Vector3 &val, long tmsec = 0);
  34.151 +	Vector3 get_value(long tmsec = 0) const;
  34.152 +
  34.153 +	// the same as get_value
  34.154 +	Vector3 operator ()(long tmsec = 0) const;
  34.155 +};
  34.156 +
  34.157 +#endif	/* GOATGFX_XFORM_NODE_H_ */
    35.1 --- a/vrchess.sln	Sat Aug 23 12:03:29 2014 +0300
    35.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.3 @@ -1,20 +0,0 @@
    35.4 -
    35.5 -Microsoft Visual Studio Solution File, Format Version 12.00
    35.6 -# Visual Studio 2012
    35.7 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vrchess", "vrchess.vcxproj", "{714906B6-FD4C-4ECC-990C-247FA46B8801}"
    35.8 -EndProject
    35.9 -Global
   35.10 -	GlobalSection(SolutionConfigurationPlatforms) = preSolution
   35.11 -		Debug|Win32 = Debug|Win32
   35.12 -		Release|Win32 = Release|Win32
   35.13 -	EndGlobalSection
   35.14 -	GlobalSection(ProjectConfigurationPlatforms) = postSolution
   35.15 -		{714906B6-FD4C-4ECC-990C-247FA46B8801}.Debug|Win32.ActiveCfg = Debug|Win32
   35.16 -		{714906B6-FD4C-4ECC-990C-247FA46B8801}.Debug|Win32.Build.0 = Debug|Win32
   35.17 -		{714906B6-FD4C-4ECC-990C-247FA46B8801}.Release|Win32.ActiveCfg = Release|Win32
   35.18 -		{714906B6-FD4C-4ECC-990C-247FA46B8801}.Release|Win32.Build.0 = Release|Win32
   35.19 -	EndGlobalSection
   35.20 -	GlobalSection(SolutionProperties) = preSolution
   35.21 -		HideSolutionNode = FALSE
   35.22 -	EndGlobalSection
   35.23 -EndGlobal
    36.1 --- a/vrchess.vcxproj	Sat Aug 23 12:03:29 2014 +0300
    36.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.3 @@ -1,117 +0,0 @@
    36.4 -<?xml version="1.0" encoding="utf-8"?>
    36.5 -<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    36.6 -  <ItemGroup Label="ProjectConfigurations">
    36.7 -    <ProjectConfiguration Include="Debug|Win32">
    36.8 -      <Configuration>Debug</Configuration>
    36.9 -      <Platform>Win32</Platform>
   36.10 -    </ProjectConfiguration>
   36.11 -    <ProjectConfiguration Include="Release|Win32">
   36.12 -      <Configuration>Release</Configuration>
   36.13 -      <Platform>Win32</Platform>
   36.14 -    </ProjectConfiguration>
   36.15 -  </ItemGroup>
   36.16 -  <PropertyGroup Label="Globals">
   36.17 -    <ProjectGuid>{714906B6-FD4C-4ECC-990C-247FA46B8801}</ProjectGuid>
   36.18 -    <Keyword>Win32Proj</Keyword>
   36.19 -    <RootNamespace>vrchess</RootNamespace>
   36.20 -  </PropertyGroup>
   36.21 -  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   36.22 -  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   36.23 -    <ConfigurationType>Application</ConfigurationType>
   36.24 -    <UseDebugLibraries>true</UseDebugLibraries>
   36.25 -    <PlatformToolset>v120</PlatformToolset>
   36.26 -    <CharacterSet>MultiByte</CharacterSet>
   36.27 -  </PropertyGroup>
   36.28 -  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   36.29 -    <ConfigurationType>Application</ConfigurationType>
   36.30 -    <UseDebugLibraries>false</UseDebugLibraries>
   36.31 -    <PlatformToolset>v120</PlatformToolset>
   36.32 -    <WholeProgramOptimization>false</WholeProgramOptimization>
   36.33 -    <CharacterSet>MultiByte</CharacterSet>
   36.34 -  </PropertyGroup>
   36.35 -  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   36.36 -  <ImportGroup Label="ExtensionSettings">
   36.37 -  </ImportGroup>
   36.38 -  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   36.39 -    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   36.40 -  </ImportGroup>
   36.41 -  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   36.42 -    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   36.43 -  </ImportGroup>
   36.44 -  <PropertyGroup Label="UserMacros" />
   36.45 -  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   36.46 -    <LinkIncremental>true</LinkIncremental>
   36.47 -  </PropertyGroup>
   36.48 -  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   36.49 -    <LinkIncremental>false</LinkIncremental>
   36.50 -  </PropertyGroup>
   36.51 -  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   36.52 -    <ClCompile>
   36.53 -      <PrecompiledHeader>
   36.54 -      </PrecompiledHeader>
   36.55 -      <WarningLevel>Level3</WarningLevel>
   36.56 -      <Optimization>Disabled</Optimization>
   36.57 -      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);USE_LIBOVR</PreprocessorDefinitions>
   36.58 -      <DisableSpecificWarnings>4996;4244;4305</DisableSpecificWarnings>
   36.59 -      <AdditionalIncludeDirectories>$(SolutionDir)\src</AdditionalIncludeDirectories>
   36.60 -    </ClCompile>
   36.61 -    <Link>
   36.62 -      <SubSystem>Console</SubSystem>
   36.63 -      <GenerateDebugInformation>true</GenerateDebugInformation>
   36.64 -      <AdditionalDependencies>opengl32.lib;freeglutd.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;libovrd.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
   36.65 -    </Link>
   36.66 -  </ItemDefinitionGroup>
   36.67 -  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   36.68 -    <ClCompile>
   36.69 -      <WarningLevel>Level3</WarningLevel>
   36.70 -      <PrecompiledHeader>
   36.71 -      </PrecompiledHeader>
   36.72 -      <Optimization>MaxSpeed</Optimization>
   36.73 -      <FunctionLevelLinking>true</FunctionLevelLinking>
   36.74 -      <IntrinsicFunctions>true</IntrinsicFunctions>
   36.75 -      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);USE_LIBOVR</PreprocessorDefinitions>
   36.76 -      <DisableSpecificWarnings>4996;4244;4305</DisableSpecificWarnings>
   36.77 -      <AdditionalIncludeDirectories>$(SolutionDir)\src</AdditionalIncludeDirectories>
   36.78 -    </ClCompile>
   36.79 -    <Link>
   36.80 -      <SubSystem>Console</SubSystem>
   36.81 -      <GenerateDebugInformation>true</GenerateDebugInformation>
   36.82 -      <EnableCOMDATFolding>true</EnableCOMDATFolding>
   36.83 -      <OptimizeReferences>true</OptimizeReferences>
   36.84 -      <AdditionalDependencies>opengl32.lib;freeglut.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;libovr.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
   36.85 -    </Link>
   36.86 -  </ItemDefinitionGroup>
   36.87 -  <ItemGroup>
   36.88 -    <ClCompile Include="src\camera.cc" />
   36.89 -    <ClCompile Include="src\game.cc" />
   36.90 -    <ClCompile Include="src\image.cc" />
   36.91 -    <ClCompile Include="src\main.cc" />
   36.92 -    <ClCompile Include="src\opengl.cc" />
   36.93 -    <ClCompile Include="src\sdr.c" />
   36.94 -    <ClCompile Include="src\texture.cc" />
   36.95 -    <ClCompile Include="src\vr\mathutil.c" />
   36.96 -    <ClCompile Include="src\vr\opt.c" />
   36.97 -    <ClCompile Include="src\vr\rbtree.c" />
   36.98 -    <ClCompile Include="src\vr\vr.c" />
   36.99 -    <ClCompile Include="src\vr\vr_libovr.c" />
  36.100 -    <ClCompile Include="src\vr\vr_modules.c" />
  36.101 -    <ClCompile Include="src\vr\vr_null.c" />
  36.102 -    <ClCompile Include="src\vr\vr_openhmd.c" />
  36.103 -  </ItemGroup>
  36.104 -  <ItemGroup>
  36.105 -    <ClInclude Include="src\camera.h" />
  36.106 -    <ClInclude Include="src\game.h" />
  36.107 -    <ClInclude Include="src\image.h" />
  36.108 -    <ClInclude Include="src\opengl.h" />
  36.109 -    <ClInclude Include="src\sdr.h" />
  36.110 -    <ClInclude Include="src\texture.h" />
  36.111 -    <ClInclude Include="src\vr\mathutil.h" />
  36.112 -    <ClInclude Include="src\vr\opt.h" />
  36.113 -    <ClInclude Include="src\vr\rbtree.h" />
  36.114 -    <ClInclude Include="src\vr\vr.h" />
  36.115 -    <ClInclude Include="src\vr\vr_impl.h" />
  36.116 -  </ItemGroup>
  36.117 -  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  36.118 -  <ImportGroup Label="ExtensionTargets">
  36.119 -  </ImportGroup>
  36.120 -</Project>
  36.121 \ No newline at end of file
    37.1 --- a/vrchess.vcxproj.filters	Sat Aug 23 12:03:29 2014 +0300
    37.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.3 @@ -1,94 +0,0 @@
    37.4 -<?xml version="1.0" encoding="utf-8"?>
    37.5 -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    37.6 -  <ItemGroup>
    37.7 -    <Filter Include="src">
    37.8 -      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
    37.9 -      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;h;inl</Extensions>
   37.10 -    </Filter>
   37.11 -    <Filter Include="src\vr">
   37.12 -      <UniqueIdentifier>{e881ab02-1a45-43f6-a15d-ee7f77256a1e}</UniqueIdentifier>
   37.13 -    </Filter>
   37.14 -  </ItemGroup>
   37.15 -  <ItemGroup>
   37.16 -    <ClCompile Include="src\main.cc">
   37.17 -      <Filter>src</Filter>
   37.18 -    </ClCompile>
   37.19 -    <ClCompile Include="src\camera.cc">
   37.20 -      <Filter>src</Filter>
   37.21 -    </ClCompile>
   37.22 -    <ClCompile Include="src\opengl.cc">
   37.23 -      <Filter>src</Filter>
   37.24 -    </ClCompile>
   37.25 -    <ClCompile Include="src\sdr.c">
   37.26 -      <Filter>src</Filter>
   37.27 -    </ClCompile>
   37.28 -    <ClCompile Include="src\game.cc">
   37.29 -      <Filter>src</Filter>
   37.30 -    </ClCompile>
   37.31 -    <ClCompile Include="src\image.cc">
   37.32 -      <Filter>src</Filter>
   37.33 -    </ClCompile>
   37.34 -    <ClCompile Include="src\texture.cc">
   37.35 -      <Filter>src</Filter>
   37.36 -    </ClCompile>
   37.37 -    <ClCompile Include="src\vr\vr.c">
   37.38 -      <Filter>src\vr</Filter>
   37.39 -    </ClCompile>
   37.40 -    <ClCompile Include="src\vr\vr_libovr.c">
   37.41 -      <Filter>src\vr</Filter>
   37.42 -    </ClCompile>
   37.43 -    <ClCompile Include="src\vr\vr_modules.c">
   37.44 -      <Filter>src\vr</Filter>
   37.45 -    </ClCompile>
   37.46 -    <ClCompile Include="src\vr\vr_null.c">
   37.47 -      <Filter>src\vr</Filter>
   37.48 -    </ClCompile>
   37.49 -    <ClCompile Include="src\vr\rbtree.c">
   37.50 -      <Filter>src\vr</Filter>
   37.51 -    </ClCompile>
   37.52 -    <ClCompile Include="src\vr\opt.c">
   37.53 -      <Filter>src\vr</Filter>
   37.54 -    </ClCompile>
   37.55 -    <ClCompile Include="src\vr\vr_openhmd.c">
   37.56 -      <Filter>src\vr</Filter>
   37.57 -    </ClCompile>
   37.58 -    <ClCompile Include="src\vr\mathutil.c">
   37.59 -      <Filter>src\vr</Filter>
   37.60 -    </ClCompile>
   37.61 -  </ItemGroup>
   37.62 -  <ItemGroup>
   37.63 -    <ClInclude Include="src\camera.h">
   37.64 -      <Filter>src</Filter>
   37.65 -    </ClInclude>
   37.66 -    <ClInclude Include="src\game.h">
   37.67 -      <Filter>src</Filter>
   37.68 -    </ClInclude>
   37.69 -    <ClInclude Include="src\image.h">
   37.70 -      <Filter>src</Filter>
   37.71 -    </ClInclude>
   37.72 -    <ClInclude Include="src\opengl.h">
   37.73 -      <Filter>src</Filter>
   37.74 -    </ClInclude>
   37.75 -    <ClInclude Include="src\sdr.h">
   37.76 -      <Filter>src</Filter>
   37.77 -    </ClInclude>
   37.78 -    <ClInclude Include="src\texture.h">
   37.79 -      <Filter>src</Filter>
   37.80 -    </ClInclude>
   37.81 -    <ClInclude Include="src\vr\vr.h">
   37.82 -      <Filter>src\vr</Filter>
   37.83 -    </ClInclude>
   37.84 -    <ClInclude Include="src\vr\vr_impl.h">
   37.85 -      <Filter>src\vr</Filter>
   37.86 -    </ClInclude>
   37.87 -    <ClInclude Include="src\vr\rbtree.h">
   37.88 -      <Filter>src\vr</Filter>
   37.89 -    </ClInclude>
   37.90 -    <ClInclude Include="src\vr\opt.h">
   37.91 -      <Filter>src\vr</Filter>
   37.92 -    </ClInclude>
   37.93 -    <ClInclude Include="src\vr\mathutil.h">
   37.94 -      <Filter>src\vr</Filter>
   37.95 -    </ClInclude>
   37.96 -  </ItemGroup>
   37.97 -</Project>
   37.98 \ No newline at end of file