goat3dgfx

changeset 0:1873dfd13f2d

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 14 Nov 2013 05:27:09 +0200
parents
children 51685f8fe859 eb75bff21824
files .hgignore Makefile src/3dschunks.h src/assload.cc src/assload.h src/curve.cc src/curve.h src/curveload.cc src/curveload.h src/datapath.cc src/datapath.h src/dataset.h src/dataset.inl src/geom.cc src/geom.h src/gfxutil.cc src/gfxutil.h src/image.cc src/image.h src/logger.cc src/logger.h src/material.cc src/material.h src/mesh.cc src/mesh.h src/meshgen.cc src/meshgen.h src/object.cc src/object.h src/opengl.cc src/opengl.h src/psyspp.cc src/psyspp.h src/rtarg.cc src/rtarg.h src/scene.cc src/scene.h src/sdrman.cc src/sdrman.h src/shader.cc src/shader.h src/texgen.cc src/texgen.h src/texman.cc src/texman.h src/texture.cc src/texture.h src/timer.cc src/timer.h src/unistate.cc src/unistate.h src/xform_node.cc src/xform_node.h
diffstat 53 files changed, 8037 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Thu Nov 14 05:27:09 2013 +0200
     1.3 @@ -0,0 +1,7 @@
     1.4 +\.o$
     1.5 +\.d$
     1.6 +\.swp$
     1.7 +\.a$
     1.8 +\.so\.
     1.9 +\.so$
    1.10 +\.dylib$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Thu Nov 14 05:27:09 2013 +0200
     2.3 @@ -0,0 +1,80 @@
     2.4 +PREFIX = /usr/local
     2.5 +
     2.6 +csrc = $(wildcard src/*.c)
     2.7 +ccsrc = $(wildcard src/*.cc)
     2.8 +obj = $(csrc:.c=.o) $(ccsrc:.cc=.o)
     2.9 +dep = $(obj:.o=.d)
    2.10 +name = goat3dgfx
    2.11 +lib_a = lib$(name).a
    2.12 +
    2.13 +so_major = 0
    2.14 +so_minor = 1
    2.15 +
    2.16 +ifeq ($(shell uname -r), Darwin)
    2.17 +	libgl = -framework OpenGL -framework GLUT -lGLEW
    2.18 +
    2.19 +	lib_so = lib$(name).dylib
    2.20 +	shared = -dynamiclib
    2.21 +else
    2.22 +	libgl = -lGL -lGLU -lglut -lGLEW
    2.23 +
    2.24 +	lib_so = lib$(name).so.$(so_major).$(so_minor)
    2.25 +	soname = lib$(name).so.$(so_major)
    2.26 +	devlink = lib$(name).so
    2.27 +	shared = -shared -Wl,-soname=$(soname)
    2.28 +	pic = -fPIC
    2.29 +endif
    2.30 +
    2.31 +
    2.32 +CFLAGS = -pedantic $(warn) $(dbg) $(pic) $(opt) $(inc) $(libs_cflags)
    2.33 +CXXFLAGS =  $(CFLAGS)
    2.34 +LDFLAGS = $(libgl) $(libs_ldflags)
    2.35 +
    2.36 +.PHONY: all
    2.37 +all: $(lib_so) $(lib_a)
    2.38 +
    2.39 +$(lib_a): $(obj)
    2.40 +	$(AR) rcs $@ $(obj)
    2.41 +
    2.42 +$(lib_so): $(obj)
    2.43 +	$(CXX) $(shared) -o $@ $(obj) $(LDFLAGS)
    2.44 +
    2.45 +-include $(dep)
    2.46 +
    2.47 +%.d: %.c
    2.48 +	@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
    2.49 +
    2.50 +%.d: %.cc
    2.51 +	@$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@
    2.52 +
    2.53 +.PHONY: clean
    2.54 +clean:
    2.55 +	rm -f $(obj) $(lib_a) $(lib_so)
    2.56 +
    2.57 +.PHONY: cleandep
    2.58 +cleandep:
    2.59 +	rm -f $(dep)
    2.60 +
    2.61 +.PHONY: install
    2.62 +install: $(lib_so) $(lib_a)
    2.63 +	mkdir -p $(DESTDIR)$(PREFIX)/lib $(DESTDIR)$(PREFIX)/include/goat3dgfx
    2.64 +	cp src/*.h src/*.inl $(DESTDIR)$(PREFIX)/include/goat3dgfx/
    2.65 +	cp $(lib_a) $(DESTDIR)$(PREFIX)/lib/$(lib_a)
    2.66 +	cp $(lib_so) $(DESTDIR)$(PREFIX)/lib/$(lib_so)
    2.67 +	[ -n "$(devlink)" ] && \
    2.68 +		cd $(DESTDIR)$(PREFIX)/lib && \
    2.69 +		rm -f $(soname) $(devlink) && \
    2.70 +		ln -s $(lib_so) $(soname) && \
    2.71 +		ln -s $(soname) $(devlink) || \
    2.72 +		true
    2.73 +
    2.74 +.PHONY: uninstall
    2.75 +uninstall:
    2.76 +	rm -f $(DESTDIR)$(PREFIX)/include/goat3dgfx/*
    2.77 +	rmdir $(DESTDIR)$(PREFIX)/include/goat3dgfx
    2.78 +	rm -f $(DESTDIR)$(PREFIX)/lib/$(lib_so)
    2.79 +	rm -f $(DESTDIR)$(PREFIX)/lib/$(lib_a)
    2.80 +	[ -n "$(devlink)" ] && \
    2.81 +		rm -f $(DESTDIR)$(PREFIX)/lib/$(soname) && \
    2.82 +		rm -f $(DESTDIR)$(PREFIX)/lib/$(devlink) || \
    2.83 +		true
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/3dschunks.h	Thu Nov 14 05:27:09 2013 +0200
     3.3 @@ -0,0 +1,160 @@
     3.4 +#ifndef _3DSCHUNKS_H_
     3.5 +#define _3DSCHUNKS_H_
     3.6 +
     3.7 +enum ChunkID {
     3.8 +	Chunk_Color_Float3					= 0x0010,	// o Floating point color
     3.9 +	Chunk_Color_Byte3					= 0x0011,	// o 24bit color
    3.10 +	Chunk_Color_GammaByte3				= 0x0012,	// o 24bit gamma corrected
    3.11 +	Chunk_Color_GammaFloat3				= 0x0013,	// o Floating point gamma corrected
    3.12 +	Chunk_PercentInt					= 0x0030,	// o Percent Chunk int 0 - 100
    3.13 +	Chunk_PercentFloat					= 0x0031,	// o Percent Chunk float 0 - 1
    3.14 +
    3.15 +	Chunk_3DSMain						= 0x4D4D,	// + Root Chunk
    3.16 +	Chunk_Main_3DSVersion				= 0x0002,	//   - 3DS Version
    3.17 +	Chunk_Main_3DEditor					= 0x3D3D,	//   + 3D Editor Chunk
    3.18 +	Chunk_Edit_Unit						= 0x0100,	//     - Unit
    3.19 +	Chunk_Edit_BGBitmap					= 0x1100,	//     - Background Bitmap
    3.20 +	Chunk_Edit_UseBGBitmap				= 0x1101,	//     - Use Background Bitmap
    3.21 +	Chunk_Edit_BGColor					= 0x1200,	//     - Background Color
    3.22 +	Chunk_Edit_UseBGColor				= 0x1201,	//     - Use Background Color
    3.23 +	Chunk_Edit_GradColor				= 0x1300,	//     - Background Gradient
    3.24 +	Chunk_Edit_UseGradColor				= 0x1301,	//     - Use Gradient Color
    3.25 +	Chunk_Edit_ShadowMapBias			= 0x1400,	//     - Shadow map bias
    3.26 +	Chunk_Edit_ShadowMapSize			= 0x1420,	//     - Shadow map size
    3.27 +	Chunk_Edit_ShadowMapSampleRange		= 0x1450,	//     - Shadow map sample range
    3.28 +	Chunk_Edit_RaytraceBias				= 0x1460,	//     - Raytrace bias
    3.29 +	Chunk_Edit_UseRaytrace				= 0x1470,	//     - Use Raytrace
    3.30 +	Chunk_Edit_AmbientColor				= 0x2100,	//     - Ambient Color
    3.31 +	Chunk_Edit_Fog						= 0x2200,	//     + Fog
    3.32 +	Chunk_Fog_FogColor					= 0x2210,	//	     - Fog Color
    3.33 +	Chunk_Edit_UseFog					= 0x2201,	//     - Use Fog
    3.34 +	Chunk_Edit_DistanceQue				= 0x2300,	//     + Distance que
    3.35 +	Chunk_Dist_DimBackground			= 0x2310,	//       - Dim Background
    3.36 +	Chunk_Edit_UseDistanceQue			= 0x2301,	//     - Use distance que
    3.37 +	Chunk_Edit_LayeredFogOptions		= 0x2302,	//     - Layered fog options
    3.38 +	Chunk_Edit_UseLayeredFog			= 0x2303,	//     - Use Layered Fog
    3.39 +	Chunk_Edit_MeshVersion				= 0x3D3E,	//     - Mesh Version
    3.40 +
    3.41 +	Chunk_Edit_Object					= 0x4000,	//     + Object
    3.42 +	Chunk_Obj_Hidden					= 0x4010,	//       - Hidden
    3.43 +	Chunk_Obj_DontCastShadows			= 0x4012,	//       - Object doesn't cast shadows
    3.44 +	Chunk_Obj_MatteObject				= 0x4013,	//       - Matte
    3.45 +	Chunk_Obj_ExternalProcessOn			= 0x4015,	//       - External Process on (?)
    3.46 +	Chunk_Obj_DontReceiveShadows		= 0x4017,	//       - doesn't reseive shadows
    3.47 +	Chunk_Obj_TriMesh					= 0x4100,	//       + TriMesh
    3.48 +	Chunk_TriMesh_VertexList			= 0x4110,	//         - Vertex List
    3.49 +	Chunk_TriMesh_FaceDesc				= 0x4120,	//         + Faces description
    3.50 +	Chunk_Face_Material					= 0x4130,	//           - Face Materials*
    3.51 +	Chunk_TriMesh_TexCoords				= 0x4140,	//         - Texture Coordinates
    3.52 +	Chunk_TriMesh_SmoothingGroup		= 0x4150,	//         - Smoothing group
    3.53 +	Chunk_TriMesh_WorldTransform		= 0x4160,	//         - Position and Orientation
    3.54 +	Chunk_TriMesh_Color					= 0x4165,   //         - Object color
    3.55 +	Chunk_TriMesh_ExternalProcessName	= 0x4181,	//         - External Process name (?)
    3.56 +	Chunk_TriMesh_ExternalProcessParams	= 0x4182,	//         - External Process parameters (?)
    3.57 +
    3.58 +	Chunk_Obj_Light						= 0x4600,	//       + Light
    3.59 +	Chunk_Light_SpotLight				= 0x4610,	//         + SpotLight
    3.60 +	Chunk_Spot_Raytrace					= 0x4627,	//           - Raytrace
    3.61 +	Chunk_Spot_CastShadows				= 0x4630,	//           - Light casts shadows
    3.62 +	Chunk_Spot_ShadowMap				= 0x4641,	//           - Shadow Map
    3.63 +	Chunk_Spot_ShowCone					= 0x4650,	//           - Show Cone
    3.64 +	Chunk_Spot_Rectangular				= 0x4651,	//           - Rectangular shaped spotlight
    3.65 +	Chunk_Spot_OverShoot				= 0x4652,	//           - Overshoot
    3.66 +	Chunk_Spot_ProjMap					= 0x4653,	//           - Projector Map
    3.67 +	Chunk_Spot_Roll						= 0x4656,	//           - Roll around dir
    3.68 +	Chunk_Spot_RaytraceBias				= 0x4658,	//           - Raytrace Bias
    3.69 +	Chunk_Light_Off						= 0x4620,	//         - Light is disabled
    3.70 +	Chunk_Light_Attenuation				= 0x4625,	//         - Attenuation enabled
    3.71 +	Chunk_Light_AttenuationStart		= 0x4659,	//         - Attenuation Start Range
    3.72 +	Chunk_Light_AttenuationEnd			= 0x465A,	//         - Attenuation End Range
    3.73 +	Chunk_Light_Intensity				= 0x465B,	//         - Light Intensity
    3.74 +
    3.75 +	Chunk_Obj_Camera					= 0x4700,	//       - Camera
    3.76 +	Chunk_Edit_ViewSettings				= 0x7001,	//     - View Settings
    3.77 +	Chunk_Edit_ViewDesc2				= 0x7011,	//     - View Description 2
    3.78 +	Chunk_Edit_ViewDesc1				= 0x7012,	//     - View Description 1
    3.79 +	Chunk_Edit_MeshWindows				= 0x7020,	//     - Mesh Windows (?)
    3.80 +
    3.81 +	Chunk_Edit_Material					= 0xAFFF,	//     + Material Block
    3.82 +	Chunk_Mat_Name						= 0xA000,	//       - Material Name
    3.83 +	Chunk_Mat_AmbientColor				= 0xA010,	//       - Ambient Color
    3.84 +	Chunk_Mat_DiffuseColor				= 0xA020,	//       - Diffuse Color
    3.85 +	Chunk_Mat_SpecularColor				= 0xA030,	//       - Specular Color
    3.86 +	Chunk_Mat_Specular					= 0xA040,	//       - Shininness (Specular Power)
    3.87 +	Chunk_Mat_SpecularIntensity			= 0xA041,	//       - Shininness Strength (specular intensity)
    3.88 +	Chunk_Mat_Transparency				= 0xA050,	//       - Transparency (alpha)
    3.89 +	Chunk_Mat_TransparencyFalloff		= 0xA052,	//       - Transparency Falloff
    3.90 +	Chunk_Mat_ReflectionBlur			= 0xA053,	//       - Reflection Blur
    3.91 +	Chunk_Mat_TwoSided					= 0xA081,	//       - Two Sided
    3.92 +	Chunk_Mat_AddTransparency			= 0xA083,	//       - ?
    3.93 +	Chunk_Mat_SelfIllumination			= 0xA084,	//       - Self Illumination (emissive)
    3.94 +	Chunk_Mat_Wireframe					= 0xA085,	//       - Render in wireframe
    3.95 +	Chunk_Mat_WireframeThickness		= 0xA087,	//       - Wire thickness
    3.96 +	Chunk_Mat_FaceMapping				= 0xA088,	//       - Apply maps to faces seperatly (ignore uv)
    3.97 +	Chunk_Mat_InTranc					= 0xA08A,	// ?
    3.98 +	Chunk_Mat_Soften					= 0xA08C,	//       - Soft Shading
    3.99 +	Chunk_Mat_WireUnits					= 0xA08E,	//       - Wire units (?)
   3.100 +	Chunk_Mat_RenderType				= 0xA100,	//       - Render Type
   3.101 +	Chunk_Mat_BumpMapPercent			= 0xA252,	//       - Bump map intensity
   3.102 +	Chunk_Mat_TextureMap				= 0xA200,	//       + Texture Map
   3.103 +	Chunk_Mat_TextureMap2				= 0xA33A,	//       + Texture Map 2
   3.104 +	Chunk_Mat_OpacityMap				= 0xA210,	//       + Opacity Map
   3.105 +	Chunk_Mat_BumpMap					= 0xA230,	//       + Bump Map
   3.106 +	Chunk_Mat_SpecularMap				= 0xA33C,	//       + Specular Intensity map
   3.107 +	Chunk_Mat_SpecularColorMap			= 0xA204,	//       + Specular color (texture) map
   3.108 +	Chunk_Mat_SelfIlluminationMap		= 0xA33D,	//       + Self Illumination Map
   3.109 +	Chunk_Mat_ReflectionMap				= 0xA220,	//       + Reflection Map
   3.110 +	Chunk_Mat_TextureMask				= 0xA33E,	//       - Texture Mask
   3.111 +	Chunk_Mat_Texture2Mask				= 0xA340,	//       - Texture 2 Mask
   3.112 +	Chunk_Mat_OpacityMask				= 0xA342,	//       - Opacity Mask
   3.113 +	Chunk_Mat_BumpMask					= 0xA344,	//       - Bump Mask
   3.114 +	Chunk_Mat_SpecularMask				= 0xA346,	//       - Specular Mask
   3.115 +	Chunk_Mat_SpecularColorMask			= 0xA348,	//       - Specular color mask
   3.116 +	Chunk_Mat_SelfIlluminationMask		= 0xA34A,	//       - Self Illumination mask
   3.117 +	Chunk_Mat_ReflectionMask			= 0xA34C,	//       - Reflection mask
   3.118 +
   3.119 +	// map subchunks								// -----------------------
   3.120 +	Chunk_Map_FileName					= 0xA300,	//         - Filename
   3.121 +	Chunk_Map_Params					= 0xA351,	//         - Parameters
   3.122 +	Chunk_Map_BlurPercent				= 0xA353,	//         - Blur ammount
   3.123 +	Chunk_Map_VScale					= 0xA354,	//         - Texture V Scale
   3.124 +	Chunk_Map_UScale					= 0xA356,	//         - Texture U Scale
   3.125 +	Chunk_Map_UOffset					= 0xA358,	//         - Texture U Offset
   3.126 +	Chunk_MAP_VOffset					= 0xA35A,	//         - Texture V Offset
   3.127 +	Chunk_Map_RotationAngle				= 0xA35C,	//         - Texture Rotation Angle
   3.128 +	Chunk_Map_RGBLumAlphaTint1			= 0xA360,	//         - RGB Luminance Alpha Tint 1
   3.129 +	Chunk_Map_RGBLumAlphaTint2			= 0xA362,	//         - RGB Luminance Alpha Tint 2
   3.130 +	Chunk_Map_RGBTintR					= 0xA364,	//         - RGB Tint R
   3.131 +	Chunk_Map_RGBTintG					= 0xA366,	//         - RGB Tint G
   3.132 +	Chunk_Map_RGBTintB					= 0xA368,	//         - RGB Tint B
   3.133 +	// map subchunks end							// -----------------------
   3.134 +
   3.135 +	Chunk_Main_Keyframer				= 0xB000,	//     + Keyframer Chunk
   3.136 +	Chunk_Key_AmbientInfo				= 0xB001,	//       - Ambient animation info
   3.137 +	Chunk_Key_MeshInfo					= 0xB002,	//       - Mesh animation info
   3.138 +	Chunk_Key_CameraInfo				= 0xB003,	//       - Camera animation info
   3.139 +	Chunk_Key_CameraTargetInfo			= 0xB004,	//       - Camera Target animation info
   3.140 +	Chunk_Key_OmniLightInfo				= 0xB005,	//       - Omni Light animation info
   3.141 +	Chunk_Key_SpotLightTargetInfo		= 0xB006,	//       - Spotlight target animation info
   3.142 +	Chunk_Key_SpotLightInfo				= 0xB007,	//       - Spotlight animation info
   3.143 +	Chunk_Key_Frames					= 0xB008,	//       - Animation Frames
   3.144 +
   3.145 +	// animation information subchunks				// -----------------------
   3.146 +	Chunk_Info_Object					= 0xB010,	//         - Object information
   3.147 +	Chunk_Info_ObjectPivot				= 0xB013,	//         - Object Pivot
   3.148 +	Chunk_Info_ObjectMorphAngle			= 0xB015,	//         - Object Morph Angle
   3.149 +	Chunk_Info_PositionTrack			= 0xB020,	//         - Position Track
   3.150 +	Chunk_Info_RotationTrack			= 0xB021,	//         - Rotation Track
   3.151 +	Chunk_Info_ScaleTrack				= 0xB022,	//         - Scaling Track
   3.152 +	Chunk_Info_FOVTrack					= 0xB023,	//         - FOV Track
   3.153 +	Chunk_Info_RollTrack				= 0xB024,	//         - Roll Track
   3.154 +	Chunk_Info_ColorTrack				= 0xB025,	//         - Color Track
   3.155 +	Chunk_Info_MorphTrack				= 0xB026,	//         - Morph Track
   3.156 +	Chunk_Info_HotSpotTrack				= 0xB027,	//         - HotSpot Track
   3.157 +	Chunk_Info_FalloffTrack				= 0xB028,	//         - Falloff Track
   3.158 +	Chunk_Info_HideTrack				= 0xB029,	//         - Hide Track
   3.159 +	Chunk_Info_HierarchyPosition		= 0xB030	//         - Hierarchy Position
   3.160 +};
   3.161 +
   3.162 +#endif	// _3DSCHUNKS_H_
   3.163 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/assload.cc	Thu Nov 14 05:27:09 2013 +0200
     4.3 @@ -0,0 +1,437 @@
     4.4 +#include <stdio.h>
     4.5 +#include "assload.h"
     4.6 +#include "logger.h"
     4.7 +#include "datapath.h"
     4.8 +
     4.9 +#ifdef USE_ASSIMP
    4.10 +
    4.11 +#include <vector>
    4.12 +#include <map>
    4.13 +#include "assimp/cimport.h"
    4.14 +#include "assimp/scene.h"
    4.15 +#include "assimp/postprocess.h"
    4.16 +#include "texman.h"
    4.17 +#include "material.h"
    4.18 +
    4.19 +using namespace std;
    4.20 +
    4.21 +static bool load_material(Material *mat, const aiMaterial *aimat);
    4.22 +static Object *load_node(const aiScene *aiscn, const aiNode *ainode);
    4.23 +static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh);
    4.24 +static Curve *load_curve(const aiScene *aiscn, const aiMesh *aimesh);
    4.25 +static bool load_bones(Mesh *mesh, const aiMesh *aimesh);
    4.26 +
    4.27 +static Vector3 assimp_vector(const aiVector3D &v);
    4.28 +static Quaternion assimp_quat(const aiQuaternion &q);
    4.29 +static Matrix4x4 assimp_matrix(const aiMatrix4x4 &aim);
    4.30 +static long assimp_time(const aiAnimation *anim, double aitime);
    4.31 +static void print_hierarchy(const aiNode *node);
    4.32 +
    4.33 +static map<string, Object*> obj_by_name;
    4.34 +static map<aiMesh*, Mesh*> mesh_by_aimesh;
    4.35 +
    4.36 +bool load_ass(Scene *scn, const char *fname)
    4.37 +{
    4.38 +	static bool init_done;
    4.39 +
    4.40 +	if(!init_done) {
    4.41 +		static aiLogStream log_stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT, 0);
    4.42 +		aiAttachLogStream(&log_stream);
    4.43 +		//aiEnableVerboseLogging(1);
    4.44 +		init_done = true;
    4.45 +	}
    4.46 +
    4.47 +	unsigned int proc_flags = aiProcess_JoinIdenticalVertices |
    4.48 +		aiProcess_CalcTangentSpace |
    4.49 +		aiProcess_Triangulate |
    4.50 +		aiProcess_SortByPType |
    4.51 +		aiProcess_FlipUVs;
    4.52 +
    4.53 +	const aiScene *aiscn = aiImportFile(datafile_path(fname).c_str(), proc_flags);
    4.54 +	if(!aiscn) {
    4.55 +		error_log("failed to load file: %s\n", fname);
    4.56 +		return false;
    4.57 +	}
    4.58 +
    4.59 +	info_log("NODE HIERARCHY:\n");
    4.60 +	print_hierarchy(aiscn->mRootNode);
    4.61 +	info_log("-------------------\n");
    4.62 +
    4.63 +	Vector3 root_pos, root_scaling(1.0, 1.0, 1.0);
    4.64 +	Quaternion root_rot;
    4.65 +
    4.66 +	if(aiscn->mRootNode) {
    4.67 +		Matrix4x4 root_matrix = assimp_matrix(aiscn->mRootNode->mTransformation);
    4.68 +		root_pos = root_matrix.get_translation();
    4.69 +		root_rot = root_matrix.get_rotation_quat();
    4.70 +		root_scaling = root_matrix.get_scaling();
    4.71 +	}
    4.72 +
    4.73 +	// load all meshes
    4.74 +	for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
    4.75 +		aiMesh *aimesh = aiscn->mMeshes[i];
    4.76 +		Mesh *mesh;
    4.77 +		Curve *curve;
    4.78 +
    4.79 +		switch(aimesh->mPrimitiveTypes) {
    4.80 +		case aiPrimitiveType_TRIANGLE:
    4.81 +			if((mesh = load_mesh(aiscn, aimesh))) {
    4.82 +				mesh_by_aimesh[aimesh] = mesh;
    4.83 +				scn->meshes.push_back(mesh);
    4.84 +			}
    4.85 +			break;
    4.86 +
    4.87 +		case aiPrimitiveType_LINE:
    4.88 +			if((curve = load_curve(aiscn, aimesh))) {
    4.89 +				scn->curves.push_back(curve);
    4.90 +			}
    4.91 +			break;
    4.92 +
    4.93 +		default:
    4.94 +			error_log("unsupported primitive type: %u\n", aimesh->mPrimitiveTypes);
    4.95 +			break;
    4.96 +		}
    4.97 +	}
    4.98 +
    4.99 +	// load all the nodes recursively
   4.100 +	for(unsigned int i=0; i<aiscn->mRootNode->mNumChildren; i++) {
   4.101 +		Object *obj = load_node(aiscn, aiscn->mRootNode->mChildren[i]);
   4.102 +		if(obj) {
   4.103 +			Object *dummy = new Object;
   4.104 +			dummy->set_name((string("dummyroot_") + string(obj->get_name())).c_str());
   4.105 +			dummy->set_position(root_pos);
   4.106 +			dummy->set_rotation(root_rot);
   4.107 +			dummy->set_scaling(root_scaling);
   4.108 +			dummy->add_child(obj);
   4.109 +
   4.110 +			obj = dummy;
   4.111 +			scn->objects.push_back(obj);
   4.112 +		}
   4.113 +	}
   4.114 +
   4.115 +	// load and attach the bones to the meshes
   4.116 +	for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
   4.117 +		aiMesh *aimesh = aiscn->mMeshes[i];
   4.118 +
   4.119 +		Mesh *mesh = mesh_by_aimesh[aimesh];
   4.120 +		load_bones(mesh, aimesh);
   4.121 +	}
   4.122 +
   4.123 +	obj_by_name.clear();
   4.124 +	mesh_by_aimesh.clear();
   4.125 +
   4.126 +	aiReleaseImport(aiscn);
   4.127 +	return true;
   4.128 +}
   4.129 +
   4.130 +static bool load_material(Material *mat, const aiMaterial *aimat)
   4.131 +{
   4.132 +	aiColor4D aicol;
   4.133 +	float shin, shin_str;
   4.134 +
   4.135 +	if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
   4.136 +		mat->diffuse = Vector3(aicol[0], aicol[1], aicol[2]);
   4.137 +	}
   4.138 +	if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) {
   4.139 +		mat->specular = Vector3(aicol[0], aicol[1], aicol[2]);
   4.140 +	}
   4.141 +
   4.142 +	unsigned int count = 1;
   4.143 +	if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) {
   4.144 +		shin_str = 1.0;
   4.145 +	}
   4.146 +	if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) {
   4.147 +		// XXX can't remember how I came up with this...
   4.148 +		mat->shininess = shin * shin_str * 0.0001 * 128.0;
   4.149 +	}
   4.150 +
   4.151 +	// load textures
   4.152 +	struct { int type; aiTextureType aitype; } textypes[] = {
   4.153 +		{TEX_DIFFUSE, aiTextureType_DIFFUSE},
   4.154 +		{TEX_NORMAL, aiTextureType_NORMALS},
   4.155 +		{TEX_SPECULAR, aiTextureType_SPECULAR}
   4.156 +	};
   4.157 +
   4.158 +	for(int i=0; i<sizeof textypes / sizeof *textypes; i++) {
   4.159 +		aiString aipath;
   4.160 +
   4.161 +		if(aiGetMaterialTexture(aimat, textypes[i].aitype, 0, &aipath) == 0) {
   4.162 +			char *tmp, *fname = aipath.data;
   4.163 +
   4.164 +			if((tmp = strrchr(fname, '/'))) {
   4.165 +				fname = tmp + 1;
   4.166 +			}
   4.167 +			if((tmp = strrchr(fname, '\\'))) {
   4.168 +				fname = tmp + 1;
   4.169 +			}
   4.170 +
   4.171 +			if(*fname) {
   4.172 +				mat->tex[textypes[i].type] = texset.get(fname);
   4.173 +			}
   4.174 +		}
   4.175 +	}
   4.176 +
   4.177 +	return true;
   4.178 +}
   4.179 +
   4.180 +static Object *load_node(const aiScene *aiscn, const aiNode *ainode)
   4.181 +{
   4.182 +	Object *obj = new Object;
   4.183 +	obj->set_name(ainode->mName.data);
   4.184 +
   4.185 +	if(ainode->mNumMeshes) {
   4.186 +		if(ainode->mNumMeshes > 1) {
   4.187 +			info_log("%s warning: node %s has more than one meshes (%u)\n", __FUNCTION__,
   4.188 +					ainode->mName.data, ainode->mNumMeshes);
   4.189 +		}
   4.190 +
   4.191 +		aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[0]];
   4.192 +		obj->set_mesh(mesh_by_aimesh[aimesh]);
   4.193 +
   4.194 +		// also grab the material of this mesh
   4.195 +		load_material(&obj->material, aiscn->mMaterials[aimesh->mMaterialIndex]);
   4.196 +	}
   4.197 +
   4.198 +	// if there are animations, grab the first and try to use it
   4.199 +	if(aiscn->mNumAnimations) {
   4.200 +		aiAnimation *aianim = aiscn->mAnimations[0];
   4.201 +		aiNodeAnim *ainodeanim = 0;
   4.202 +		for(unsigned int i=0; i<aianim->mNumChannels; i++) {
   4.203 +			if(strcmp(aianim->mChannels[i]->mNodeName.data, ainode->mName.data) == 0) {
   4.204 +				ainodeanim = aianim->mChannels[i];
   4.205 +				break;
   4.206 +			}
   4.207 +		}
   4.208 +
   4.209 +		if(ainodeanim) {
   4.210 +			// load all position (translation) keyframes
   4.211 +			for(unsigned int i=0; i<ainodeanim->mNumPositionKeys; i++) {
   4.212 +				Vector3 pos = assimp_vector(ainodeanim->mPositionKeys[i].mValue);
   4.213 +				long msec = assimp_time(aianim, ainodeanim->mPositionKeys[i].mTime);
   4.214 +				obj->set_position(pos, msec);
   4.215 +			}
   4.216 +
   4.217 +			// load all rotation keyframes
   4.218 +			for(unsigned int i=0; i<ainodeanim->mNumRotationKeys; i++) {
   4.219 +				Quaternion rot = assimp_quat(ainodeanim->mRotationKeys[i].mValue);
   4.220 +				if(rot.length_sq() < SMALL_NUMBER) {
   4.221 +					continue;
   4.222 +				}
   4.223 +				rot.normalize();
   4.224 +				long msec = assimp_time(aianim, ainodeanim->mRotationKeys[i].mTime);
   4.225 +				obj->set_rotation(rot, msec);
   4.226 +			}
   4.227 +
   4.228 +			// load all scaling keyframes
   4.229 +			for(unsigned int i=0; i<ainodeanim->mNumScalingKeys; i++) {
   4.230 +				Vector3 scale = assimp_vector(ainodeanim->mScalingKeys[i].mValue);
   4.231 +				long msec = assimp_time(aianim, ainodeanim->mScalingKeys[i].mTime);
   4.232 +				obj->set_scaling(scale, msec);
   4.233 +			}
   4.234 +
   4.235 +			obj->set_extrapolator(EXTRAP_REPEAT);	// loop animation
   4.236 +		} else {
   4.237 +			Matrix4x4 local_matrix = assimp_matrix(ainode->mTransformation);
   4.238 +			obj->set_local_matrix(local_matrix);
   4.239 +		}
   4.240 +	}
   4.241 +
   4.242 +	/* recurse to all children */
   4.243 +	for(unsigned int i=0; i<ainode->mNumChildren; i++) {
   4.244 +		Object *child = load_node(aiscn, ainode->mChildren[i]);
   4.245 +		if(child) {
   4.246 +			obj->add_child(child);
   4.247 +		}
   4.248 +	}
   4.249 +
   4.250 +	obj_by_name[obj->get_name()] = obj;
   4.251 +	return obj;
   4.252 +}
   4.253 +
   4.254 +static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh)
   4.255 +{
   4.256 +	Mesh *mesh = new Mesh;
   4.257 +
   4.258 +	int num_verts = aimesh->mNumVertices;
   4.259 +	int num_faces = aimesh->mNumFaces;
   4.260 +
   4.261 +	mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices);
   4.262 +
   4.263 +	if(aimesh->mNormals) {
   4.264 +		mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals);
   4.265 +	}
   4.266 +	if(aimesh->mTangents) {
   4.267 +		mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents);
   4.268 +	}
   4.269 +	if(aimesh->mTextureCoords[0]) {
   4.270 +		mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]);
   4.271 +	}
   4.272 +
   4.273 +	if(aimesh->mBones) {
   4.274 +		float *weights = mesh->set_attrib_data(MESH_ATTR_BONEWEIGHTS, 4, num_verts, 0);
   4.275 +		float *boneidx = mesh->set_attrib_data(MESH_ATTR_BONEIDX, 4, num_verts, 0);
   4.276 +
   4.277 +		memset(weights, 0, num_verts * 4 * sizeof *weights);
   4.278 +		memset(boneidx, 0, num_verts * 4 * sizeof *boneidx);
   4.279 +
   4.280 +		int *vertex_bone_count = new int[num_verts];
   4.281 +		memset(vertex_bone_count, 0, num_verts * sizeof *vertex_bone_count);
   4.282 +
   4.283 +		for(unsigned int i=0; i<aimesh->mNumBones; i++) {
   4.284 +			aiBone *aibone = aimesh->mBones[i];
   4.285 +
   4.286 +			// for every vertex affected by this bone:
   4.287 +			for(unsigned int j=0; j<aibone->mNumWeights; j++) {
   4.288 +				aiVertexWeight *aiweight = aibone->mWeights + j;
   4.289 +				int vidx = aiweight->mVertexId;
   4.290 +				int vert_boneidx = vertex_bone_count[vidx];
   4.291 +				if(vert_boneidx >= 4) {
   4.292 +					error_log("WARNING vertex with more than 4 bones found\n");
   4.293 +					continue;
   4.294 +				}
   4.295 +
   4.296 +				weights[vidx * 4 + vert_boneidx] = aiweight->mWeight;
   4.297 +				boneidx[vidx * 4 + vert_boneidx] = (float)i;
   4.298 +				vertex_bone_count[vidx]++;
   4.299 +			}
   4.300 +		}
   4.301 +
   4.302 +		delete [] vertex_bone_count;
   4.303 +
   4.304 +		// normalize weights
   4.305 +		for(int i=0; i<num_verts; i++) {
   4.306 +
   4.307 +			float wsum = 0.0f;
   4.308 +
   4.309 +			for(int j=0; j<4; j++) {
   4.310 +				wsum += weights[i * 4 + j];
   4.311 +			}
   4.312 +
   4.313 +			if(1.0 - wsum > 1e-4) {
   4.314 +				error_log("WARNING vertex with weights < 1 (%f), normalizing...\n", wsum);
   4.315 +
   4.316 +				if(wsum < 1e-6) {
   4.317 +					// this is clearly broken, let's use the first bone in full
   4.318 +					weights[i * 4] = 1.0;
   4.319 +				} else {
   4.320 +					weights[i * 4] /= wsum;
   4.321 +					weights[i * 4 + 1] /= wsum;
   4.322 +					weights[i * 4 + 2] /= wsum;
   4.323 +					weights[i * 4 + 3] /= wsum;
   4.324 +				}
   4.325 +			}
   4.326 +		}
   4.327 +	}
   4.328 +
   4.329 +	unsigned int *iptr = mesh->set_index_data(num_faces * 3);
   4.330 +	for(int i=0; i<num_faces; i++) {
   4.331 +		for(int j=0; j<3; j++) {
   4.332 +			*iptr++ = aimesh->mFaces[i].mIndices[j];
   4.333 +		}
   4.334 +	}
   4.335 +
   4.336 +	return mesh;
   4.337 +}
   4.338 +
   4.339 +static Curve *load_curve(const aiScene *aiscn, const aiMesh *aimesh)
   4.340 +{
   4.341 +	Curve *curve = new Curve;
   4.342 +
   4.343 +	for(unsigned int i=0; i<aimesh->mNumVertices; i++) {
   4.344 +		Vector3 pt = assimp_vector(aimesh->mVertices[i]);
   4.345 +		curve->add_point(pt);
   4.346 +	}
   4.347 +	info_log("loaded curve with %d points\n", aimesh->mNumVertices);
   4.348 +
   4.349 +	return curve;
   4.350 +}
   4.351 +
   4.352 +static bool load_bones(Mesh *mesh, const aiMesh *aimesh)
   4.353 +{
   4.354 +	if(!aimesh->mNumBones) {
   4.355 +		return false;
   4.356 +	}
   4.357 +
   4.358 +	for(unsigned int i=0; i<aimesh->mNumBones; i++) {
   4.359 +		aiBone *aibone = aimesh->mBones[i];
   4.360 +		Object *obj = obj_by_name[aibone->mName.data];
   4.361 +		if(!obj) {
   4.362 +			error_log("bone %s not found\n", aibone->mName.data);
   4.363 +			continue;
   4.364 +		}
   4.365 +
   4.366 +		obj->set_bone_matrix(assimp_matrix(aibone->mOffsetMatrix));
   4.367 +		mesh->add_bone(obj);
   4.368 +
   4.369 +		info_log("adding bone: %s\n", obj->get_name());
   4.370 +	}
   4.371 +
   4.372 +	return true;
   4.373 +}
   4.374 +
   4.375 +static Vector3 assimp_vector(const aiVector3D &v)
   4.376 +{
   4.377 +	return Vector3(v[0], v[1], v[2]);
   4.378 +}
   4.379 +
   4.380 +static Quaternion assimp_quat(const aiQuaternion &q)
   4.381 +{
   4.382 +	return Quaternion(q.w, Vector3(q.x, q.y, q.z));
   4.383 +}
   4.384 +
   4.385 +static Matrix4x4 assimp_matrix(const aiMatrix4x4 &aim)
   4.386 +{
   4.387 +	Matrix4x4 m;
   4.388 +	memcpy(m[0], &aim, 16 * sizeof(float));
   4.389 +	return m;
   4.390 +}
   4.391 +
   4.392 +/* convert an assimp keyframe time (ticks) into milliseconds */
   4.393 +static long assimp_time(const aiAnimation *anim, double aitime)
   4.394 +{
   4.395 +	double sec;
   4.396 +	if(anim->mTicksPerSecond < 1e-6) {
   4.397 +		// assume time is in frames?
   4.398 +		sec = aitime / 30.0;
   4.399 +	} else {
   4.400 +		sec = aitime / anim->mTicksPerSecond;
   4.401 +	}
   4.402 +	return (long)(sec * 1000.0);
   4.403 +}
   4.404 +
   4.405 +static void print_hierarchy(const aiNode *node)
   4.406 +{
   4.407 +	static int lvl;
   4.408 +	static int lvlopen[256];
   4.409 +
   4.410 +	for(int i=0; i<lvl; i++) {
   4.411 +		putchar(' ');
   4.412 +		if(lvlopen[i]) {
   4.413 +			putchar(i >= lvl - 1 ? '+' : '|');
   4.414 +		} else {
   4.415 +			putchar(i >= lvl - 1 ? '+' : ' ');
   4.416 +		}
   4.417 +	}
   4.418 +	info_log("- \"%s\"\n", node->mName.data);
   4.419 +
   4.420 +	lvlopen[lvl] = 1;
   4.421 +
   4.422 +	lvl++;
   4.423 +	for(unsigned int i=0; i<node->mNumChildren; i++) {
   4.424 +		if(i == node->mNumChildren - 1) {
   4.425 +			lvlopen[lvl - 1] = 0;
   4.426 +		}
   4.427 +		print_hierarchy(node->mChildren[i]);
   4.428 +	}
   4.429 +	lvl--;
   4.430 +}
   4.431 +
   4.432 +#else	// !defined USE_ASSIMP
   4.433 +
   4.434 +bool load_ass(Scene *scn, const char *fname)
   4.435 +{
   4.436 +	error_log("load_ass: assimp support not compiled in\n");
   4.437 +	return false;
   4.438 +}
   4.439 +
   4.440 +#endif
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/assload.h	Thu Nov 14 05:27:09 2013 +0200
     5.3 @@ -0,0 +1,9 @@
     5.4 +#ifndef ASSLOAD_H_
     5.5 +#define ASSLOAD_H_
     5.6 +
     5.7 +#include <vector>
     5.8 +#include "scene.h"
     5.9 +
    5.10 +bool load_ass(Scene *scn, const char *fname);
    5.11 +
    5.12 +#endif	// ASSLOAD_H_
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/curve.cc	Thu Nov 14 05:27:09 2013 +0200
     6.3 @@ -0,0 +1,316 @@
     6.4 +#include <float.h>
     6.5 +#include <assert.h>
     6.6 +#include "curve.h"
     6.7 +#include "opengl.h"
     6.8 +#include "shader.h"
     6.9 +#include "logger.h"
    6.10 +
    6.11 +#define DEF_THICKNESS	0.075
    6.12 +#define DEF_SEGM_SUB	3
    6.13 +#define DEF_RING_SUB	6
    6.14 +
    6.15 +Curve::Curve()
    6.16 +{
    6.17 +	thickness = DEF_THICKNESS;
    6.18 +	mesh_valid = false;
    6.19 +	lengths_valid = false;
    6.20 +
    6.21 +	bbox_valid = false;
    6.22 +
    6.23 +	segm_subdiv = DEF_SEGM_SUB;
    6.24 +	ring_subdiv = DEF_RING_SUB;
    6.25 +}
    6.26 +
    6.27 +Curve::Curve(const Vector3 *points, int num_points)
    6.28 +{
    6.29 +	thickness = DEF_THICKNESS;
    6.30 +	mesh_valid = false;
    6.31 +	lengths_valid = false;
    6.32 +
    6.33 +	bbox_valid = false;
    6.34 +
    6.35 +	segm_subdiv = DEF_SEGM_SUB;
    6.36 +	ring_subdiv = DEF_RING_SUB;
    6.37 +
    6.38 +	for(int i=0; i<num_points; i++) {
    6.39 +		add_point(points[i]);
    6.40 +	}
    6.41 +}
    6.42 +
    6.43 +Curve::Curve(const Vector2 *points, int num_points)
    6.44 +{
    6.45 +	thickness = DEF_THICKNESS;
    6.46 +	mesh_valid = false;
    6.47 +	lengths_valid = false;
    6.48 +
    6.49 +	bbox_valid = false;
    6.50 +
    6.51 +	segm_subdiv = DEF_SEGM_SUB;
    6.52 +	ring_subdiv = DEF_RING_SUB;
    6.53 +
    6.54 +	for(int i=0; i<num_points; i++) {
    6.55 +		add_point(Vector3(points[i].x, points[i].y, 0.0));
    6.56 +	}
    6.57 +}
    6.58 +
    6.59 +void Curve::set_name(const char *name)
    6.60 +{
    6.61 +	this->name = name;
    6.62 +}
    6.63 +
    6.64 +const char *Curve::get_name() const
    6.65 +{
    6.66 +	return name.c_str();
    6.67 +}
    6.68 +
    6.69 +bool Curve::empty() const
    6.70 +{
    6.71 +	return cv.empty();
    6.72 +}
    6.73 +
    6.74 +void Curve::set_thickness(float thickness)
    6.75 +{
    6.76 +	this->thickness = thickness;
    6.77 +}
    6.78 +
    6.79 +void Curve::set_subdiv(int seg, int ring)
    6.80 +{
    6.81 +	if(seg < 1) seg = 1;
    6.82 +	if(ring < 3) ring = 3;
    6.83 +
    6.84 +	segm_subdiv = seg;
    6.85 +	ring_subdiv = ring;
    6.86 +}
    6.87 +
    6.88 +void Curve::clear()
    6.89 +{
    6.90 +	mesh_valid = false;
    6.91 +	lengths_valid = false;
    6.92 +	bbox_valid = false;
    6.93 +	cv.clear();
    6.94 +}
    6.95 +
    6.96 +void Curve::add_point(const Vector3 &pt)
    6.97 +{
    6.98 +	cv.push_back(pt);
    6.99 +	mesh_valid = false;
   6.100 +	lengths_valid = false;
   6.101 +	bbox_valid = false;
   6.102 +}
   6.103 +
   6.104 +Vector3 &Curve::get_point(int idx)
   6.105 +{
   6.106 +	mesh_valid = false;
   6.107 +	lengths_valid = false;
   6.108 +	bbox_valid = false;
   6.109 +	return cv[idx];
   6.110 +}
   6.111 +
   6.112 +const Vector3 &Curve::get_point(int idx) const
   6.113 +{
   6.114 +	return cv[idx];
   6.115 +}
   6.116 +
   6.117 +int Curve::get_count() const
   6.118 +{
   6.119 +	return (int)cv.size();
   6.120 +}
   6.121 +
   6.122 +Vector3 &Curve::operator[] (int idx)
   6.123 +{
   6.124 +	return get_point(idx);
   6.125 +}
   6.126 +
   6.127 +const Vector3 &Curve::operator[] (int idx) const
   6.128 +{
   6.129 +	return get_point(idx);
   6.130 +}
   6.131 +
   6.132 +void Curve::get_bbox(Vector3 *bbmin, Vector3 *bbmax) const
   6.133 +{
   6.134 +	if(!bbox_valid) {
   6.135 +		this->bbmin = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
   6.136 +		this->bbmax = -this->bbmin;
   6.137 +
   6.138 +		for(size_t i=0; i<cv.size(); i++) {
   6.139 +			for(int j=0; j<3; j++) {
   6.140 +				if(cv[i][j] < this->bbmin[j]) {
   6.141 +					this->bbmin[j] = cv[i][j];
   6.142 +				}
   6.143 +				if(cv[i][j] > this->bbmax[j]) {
   6.144 +					this->bbmax[j] = cv[i][j];
   6.145 +				}
   6.146 +			}
   6.147 +		}
   6.148 +		bbox_valid = true;
   6.149 +	}
   6.150 +
   6.151 +	if(bbmin) *bbmin = this->bbmin;
   6.152 +	if(bbmax) *bbmax = this->bbmax;
   6.153 +}
   6.154 +
   6.155 +void Curve::normalize()
   6.156 +{
   6.157 +	get_bbox(0, 0);	// force validation of the bounding box
   6.158 +
   6.159 +	float len = (bbmax - bbmin).length() * 0.5;
   6.160 +	if(len == 0.0) {
   6.161 +		return;
   6.162 +	}
   6.163 +
   6.164 +	for(size_t i=0; i<cv.size(); i++) {
   6.165 +		get_point(i) /= len;
   6.166 +	}
   6.167 +}
   6.168 +
   6.169 +Vector3 Curve::get_pos(float t) const
   6.170 +{
   6.171 +	if(cv.empty()) {
   6.172 +		return Vector3(0, 0, 0);
   6.173 +	}
   6.174 +	if(cv.size() == 1 || t <= 0.0) {
   6.175 +		return cv[0];
   6.176 +	}
   6.177 +	if(t >= 1.0) {
   6.178 +		return cv.back();
   6.179 +	}
   6.180 +
   6.181 +	t = reparametrize(t);
   6.182 +
   6.183 +	int numcv = (int)cv.size();
   6.184 +	int idx0 = t * (numcv - 1);
   6.185 +	int idx1 = idx0 + 1;
   6.186 +
   6.187 +	int idx_prev = idx0 <= 0 ? idx0 : idx0 - 1;
   6.188 +	int idx_next = idx1 >= numcv - 1 ? idx1 : idx1 + 1;
   6.189 +
   6.190 +	float dt = 1.0 / (float)(numcv - 1);
   6.191 +
   6.192 +	float t0 = (float)idx0 * dt;
   6.193 +	float t1 = (float)idx1 * dt;
   6.194 +
   6.195 +	t = (t - t0) / (t1 - t0);
   6.196 +	if(t < 0.0) t = 0.0;
   6.197 +	if(t > 1.0) t = 1.0;
   6.198 +
   6.199 +	//return catmull_rom_spline(cv[idx_prev], cv[idx0], cv[idx1], cv[idx_next], t);
   6.200 +	return bspline(cv[idx_prev], cv[idx0], cv[idx1], cv[idx_next], t);
   6.201 +}
   6.202 +
   6.203 +Vector3 Curve::operator() (float t) const
   6.204 +{
   6.205 +	return get_pos(t);
   6.206 +}
   6.207 +
   6.208 +void Curve::draw() const
   6.209 +{
   6.210 +	update_mesh();
   6.211 +	if(!mesh_valid) {
   6.212 +		return;
   6.213 +	}
   6.214 +
   6.215 +	mesh.draw();
   6.216 +}
   6.217 +
   6.218 +
   6.219 +float Curve::reparametrize(float t) const
   6.220 +{
   6.221 +	calc_cvlengths();
   6.222 +	return t;	// TODO
   6.223 +}
   6.224 +
   6.225 +void Curve::calc_cvlengths() const
   6.226 +{
   6.227 +	if(lengths_valid || cv.empty()) {
   6.228 +		return;
   6.229 +	}
   6.230 +
   6.231 +	length.clear();
   6.232 +	length.resize(cv.size());
   6.233 +
   6.234 +	length[0] = 0;
   6.235 +	for(size_t i=1; i<cv.size(); i++) {
   6.236 +		length[i] = length[i - 1] + (cv[i] - cv[i - 1]).length();
   6.237 +	}
   6.238 +
   6.239 +	lengths_valid = true;
   6.240 +}
   6.241 +
   6.242 +void Curve::update_mesh() const
   6.243 +{
   6.244 +	if(mesh_valid) return;
   6.245 +
   6.246 +	if(cv.size() < 2) {
   6.247 +		return;
   6.248 +	}
   6.249 +
   6.250 +	mesh.clear();
   6.251 +
   6.252 +	int nsub = segm_subdiv * (cv.size() - 1);
   6.253 +	int num_rings = nsub + 1;
   6.254 +
   6.255 +	int num_verts = ring_subdiv * num_rings;
   6.256 +	int num_quads = ring_subdiv * nsub;
   6.257 +	int num_tri = num_quads * 2;
   6.258 +	int num_idx = num_tri * 3;
   6.259 +
   6.260 +	float *varr = mesh.set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts);
   6.261 +	float *narr = mesh.set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts);
   6.262 +	float *tcarr = mesh.set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts);
   6.263 +	unsigned int *idxarr = mesh.set_index_data(num_idx);
   6.264 +
   6.265 +	float t = 0.0;
   6.266 +	float dt = 1.0 / (float)(num_rings - 1);
   6.267 +
   6.268 +	for(int i=0; i<num_rings; i++) {
   6.269 +		Vector3 p = get_pos(t);
   6.270 +		Vector3 dir = (get_pos(t + dt) - p).normalized();
   6.271 +
   6.272 +		Vector3 up = Vector3(0, 0, 1);
   6.273 +		float updotdir = dot_product(up, dir);
   6.274 +		if(1.0 - fabs(updotdir) < 1e-4) {
   6.275 +			up = Vector3(0, 1, 0);
   6.276 +		}
   6.277 +		Vector3 right = cross_product(up, dir).normalized();
   6.278 +		up = cross_product(dir, right);
   6.279 +
   6.280 +		for(int j=0; j<ring_subdiv; j++) {
   6.281 +			float u = (float)j / (float)ring_subdiv * M_PI * 2.0;
   6.282 +			Quaternion qrot(dir, u);
   6.283 +			Vector3 v = p + right.transformed(qrot) * thickness;
   6.284 +
   6.285 +			*varr++ = v.x;
   6.286 +			*varr++ = v.y;
   6.287 +			*varr++ = v.z;
   6.288 +
   6.289 +			Vector3 norm = (v - p).normalized();
   6.290 +			*narr++ = norm.x;
   6.291 +			*narr++ = norm.y;
   6.292 +			*narr++ = norm.z;
   6.293 +
   6.294 +			*tcarr++ = u;
   6.295 +			*tcarr++ = t;
   6.296 +
   6.297 +			if(i < nsub) {
   6.298 +				int quad = i * ring_subdiv + j;
   6.299 +
   6.300 +				int v0 = quad;
   6.301 +				int v1 = i * ring_subdiv + ((j + 1) % ring_subdiv);
   6.302 +				int v2 = (i + 1) * ring_subdiv + ((j + 1) % ring_subdiv);
   6.303 +				int v3 = (i + 1) * ring_subdiv + j;
   6.304 +
   6.305 +				idxarr[quad * 6] = v0;
   6.306 +				idxarr[quad * 6 + 1] = v1;
   6.307 +				idxarr[quad * 6 + 2] = v2;
   6.308 +
   6.309 +				idxarr[quad * 6 + 3] = v0;
   6.310 +				idxarr[quad * 6 + 4] = v2;
   6.311 +				idxarr[quad * 6 + 5] = v3;
   6.312 +			}
   6.313 +		}
   6.314 +
   6.315 +		t += dt;
   6.316 +	}
   6.317 +
   6.318 +	mesh_valid = true;
   6.319 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/curve.h	Thu Nov 14 05:27:09 2013 +0200
     7.3 @@ -0,0 +1,64 @@
     7.4 +#ifndef CURVE_H_
     7.5 +#define CURVE_H_
     7.6 +
     7.7 +#include <string>
     7.8 +#include <vector>
     7.9 +#include "vmath/vmath.h"
    7.10 +#include "mesh.h"
    7.11 +
    7.12 +class Curve {
    7.13 +private:
    7.14 +	std::string name;
    7.15 +
    7.16 +	std::vector<Vector3> cv;
    7.17 +	float thickness;
    7.18 +
    7.19 +	int segm_subdiv, ring_subdiv;
    7.20 +
    7.21 +	/// normalized arc-lengths of each control vertex from the beginning
    7.22 +	mutable std::vector<float> length;
    7.23 +	mutable bool lengths_valid;
    7.24 +
    7.25 +	mutable Vector3 bbmin, bbmax;
    7.26 +	mutable bool bbox_valid;
    7.27 +
    7.28 +	mutable Mesh mesh;
    7.29 +	mutable bool mesh_valid;
    7.30 +
    7.31 +	float reparametrize(float t) const;
    7.32 +
    7.33 +	void calc_cvlengths() const;
    7.34 +	void update_mesh() const;
    7.35 +
    7.36 +public:
    7.37 +	Curve();
    7.38 +	Curve(const Vector3 *points, int num_points);
    7.39 +	Curve(const Vector2 *points, int num_points);
    7.40 +
    7.41 +	void set_name(const char *name);
    7.42 +	const char *get_name() const;
    7.43 +
    7.44 +	bool empty() const;
    7.45 +
    7.46 +	void set_thickness(float thickness);
    7.47 +	void set_subdiv(int seg, int ring);
    7.48 +
    7.49 +	void clear();
    7.50 +	void add_point(const Vector3 &pt);
    7.51 +	Vector3 &get_point(int idx);
    7.52 +	const Vector3 &get_point(int idx) const;
    7.53 +	int get_count() const;
    7.54 +
    7.55 +	Vector3 &operator[] (int idx);
    7.56 +	const Vector3 &operator[] (int idx) const;
    7.57 +
    7.58 +	void get_bbox(Vector3 *bbmin, Vector3 *bbmax) const;
    7.59 +	void normalize();
    7.60 +
    7.61 +	Vector3 get_pos(float t) const;
    7.62 +	Vector3 operator() (float t) const;
    7.63 +
    7.64 +	void draw() const;
    7.65 +};
    7.66 +
    7.67 +#endif	// CURVE_H_
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/curveload.cc	Thu Nov 14 05:27:09 2013 +0200
     8.3 @@ -0,0 +1,195 @@
     8.4 +#include <string>
     8.5 +#include <assert.h>
     8.6 +#include <stdint.h>
     8.7 +#include "curveload.h"
     8.8 +#include "3dschunks.h"
     8.9 +#include "logger.h"
    8.10 +
    8.11 +static uint32_t read_counter;
    8.12 +
    8.13 +struct ChunkHeader {
    8.14 +	ChunkID id;
    8.15 +	uint32_t size;
    8.16 +};
    8.17 +
    8.18 +#define HEADER_SIZE		6
    8.19 +
    8.20 +// local function prototypes
    8.21 +static uint8_t read_byte(FILE *file);
    8.22 +static uint16_t read_int16(FILE *file);
    8.23 +static uint32_t read_int32(FILE *file);
    8.24 +static float read_float(FILE *file);
    8.25 +static Vector3 read_vector(FILE *file, bool flip_yz = false);
    8.26 +static std::string read_string(FILE *file);
    8.27 +static ChunkHeader read_chunk_header(FILE *file);
    8.28 +static void skip_chunk(FILE *file, const ChunkHeader &chunk);
    8.29 +static Curve *read_curve(FILE *file, const ChunkHeader &ch);
    8.30 +
    8.31 +static bool eof;
    8.32 +
    8.33 +bool load_curves(Scene *scn, const char *fname)
    8.34 +{
    8.35 +	FILE *file = fopen(fname, "rb");
    8.36 +	if(!file) {
    8.37 +		error_log("failed to open curves scene file: %s\n", fname);
    8.38 +		return false;
    8.39 +	}
    8.40 +	eof = false;
    8.41 +
    8.42 +	ChunkHeader chunk;
    8.43 +
    8.44 +	chunk = read_chunk_header(file);
    8.45 +	if(chunk.id != Chunk_3DSMain) {
    8.46 +		fclose(file);
    8.47 +		return false;
    8.48 +	}
    8.49 +
    8.50 +	while(!eof) {
    8.51 +		chunk = read_chunk_header(file);
    8.52 +
    8.53 +		Curve *curve;
    8.54 +
    8.55 +		switch(chunk.id) {
    8.56 +		case Chunk_Main_3DEditor:
    8.57 +			break;	// dont skip
    8.58 +
    8.59 +		case Chunk_Edit_Object:
    8.60 +			if((curve = read_curve(file, chunk))) {
    8.61 +				scn->curves.push_back(curve);
    8.62 +			}
    8.63 +			break;
    8.64 +
    8.65 +		default:
    8.66 +			skip_chunk(file, chunk);
    8.67 +		}
    8.68 +	}
    8.69 +
    8.70 +	fclose(file);
    8.71 +    return true;
    8.72 +}
    8.73 +
    8.74 +static uint8_t read_byte(FILE *fp) {
    8.75 +	uint8_t v;
    8.76 +	if(fread(&v, 1, 1, fp) <= 0) {
    8.77 +		eof = true;
    8.78 +		return 0;
    8.79 +	}
    8.80 +	read_counter++;
    8.81 +	return v;
    8.82 +}
    8.83 +
    8.84 +static uint16_t read_int16(FILE *fp) {
    8.85 +	uint16_t v;
    8.86 +	if(fread(&v, 2, 1, fp) <= 0) {
    8.87 +		eof = true;
    8.88 +		return 0;
    8.89 +	}
    8.90 +	read_counter += 2;
    8.91 +	return v;
    8.92 +}
    8.93 +
    8.94 +static uint32_t read_int32(FILE *fp) {
    8.95 +	uint32_t v;
    8.96 +	if(fread(&v, 4, 1, fp) <= 0) {
    8.97 +		eof = true;
    8.98 +		return 0;
    8.99 +	}
   8.100 +	read_counter += 4;
   8.101 +	return v;
   8.102 +}
   8.103 +
   8.104 +static float read_float(FILE *fp)
   8.105 +{
   8.106 +	int32_t tmp = read_int32(fp);
   8.107 +	return *((float*)&tmp);
   8.108 +}
   8.109 +
   8.110 +static Vector3 read_vector(FILE *file, bool flip_yz)
   8.111 +{
   8.112 +	Vector3 vector;
   8.113 +	vector.x = read_float(file);
   8.114 +	if(!flip_yz) vector.y = read_float(file);
   8.115 +	vector.z = read_float(file);
   8.116 +	if(flip_yz) vector.y = read_float(file);
   8.117 +	return vector;
   8.118 +}
   8.119 +
   8.120 +static std::string read_string(FILE *file)
   8.121 +{
   8.122 +	std::string str;
   8.123 +	char c;
   8.124 +	while((c = (char)read_byte(file))) {
   8.125 +		str.push_back(c);
   8.126 +	}
   8.127 +	read_counter++;
   8.128 +
   8.129 +	return str;
   8.130 +}
   8.131 +
   8.132 +static ChunkHeader read_chunk_header(FILE *file)
   8.133 +{
   8.134 +	ChunkHeader chunk;
   8.135 +	chunk.id = (ChunkID)read_int16(file);
   8.136 +	chunk.size = read_int32(file);
   8.137 +	return chunk;
   8.138 +}
   8.139 +
   8.140 +static void skip_chunk(FILE *file, const ChunkHeader &chunk)
   8.141 +{
   8.142 +	if(eof) return;
   8.143 +	fseek(file, chunk.size - HEADER_SIZE, SEEK_CUR);
   8.144 +	read_counter += chunk.size - HEADER_SIZE;
   8.145 +}
   8.146 +
   8.147 +static Curve *read_curve(FILE *file, const ChunkHeader &ch)
   8.148 +{
   8.149 +	read_counter = HEADER_SIZE;	// reset the global read counter
   8.150 +
   8.151 +	std::string name = read_string(file);
   8.152 +
   8.153 +	ChunkHeader chunk;
   8.154 +	chunk = read_chunk_header(file);
   8.155 +	if(chunk.id == Chunk_Obj_TriMesh) {
   8.156 +		// object is a trimesh... load it
   8.157 +		Vector3 *varray = 0;
   8.158 +		uint32_t vertex_count = 0;
   8.159 +
   8.160 +		uint32_t obj_chunk_size = ch.size;
   8.161 +
   8.162 +		while(read_counter < obj_chunk_size) {	// make sure we only read subchunks of this object chunk
   8.163 +			chunk = read_chunk_header(file);
   8.164 +
   8.165 +            switch(chunk.id) {
   8.166 +			case Chunk_TriMesh_VertexList:
   8.167 +				vertex_count = (uint32_t)read_int16(file);
   8.168 +				varray = new Vector3[vertex_count];
   8.169 +
   8.170 +				for(uint32_t i=0; i<vertex_count; i++) {
   8.171 +					varray[i] = read_vector(file);
   8.172 +				}
   8.173 +
   8.174 +				break;
   8.175 +
   8.176 +			case Chunk_TriMesh_FaceDesc:
   8.177 +				// it is a real object not a curve since it has triangles
   8.178 +				delete [] varray;
   8.179 +				varray = 0;
   8.180 +				break;
   8.181 +
   8.182 +			default:
   8.183 +				skip_chunk(file, chunk);
   8.184 +			}
   8.185 +		}
   8.186 +
   8.187 +		if(varray) {
   8.188 +			Curve *curve = new Curve;
   8.189 +			curve->set_name(name.c_str());
   8.190 +			for(uint32_t i=0; i<vertex_count; i++) {
   8.191 +				curve->add_point(varray[i]);
   8.192 +			}
   8.193 +			return curve;
   8.194 +		}
   8.195 +	}
   8.196 +
   8.197 +	return 0;
   8.198 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/curveload.h	Thu Nov 14 05:27:09 2013 +0200
     9.3 @@ -0,0 +1,8 @@
     9.4 +#ifndef CURVELOAD_H_
     9.5 +#define CURVELOAD_H_
     9.6 +
     9.7 +#include "scene.h"
     9.8 +
     9.9 +bool load_curves(Scene *scn, const char *fname);
    9.10 +
    9.11 +#endif	// CURVELOAD_H_
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/datapath.cc	Thu Nov 14 05:27:09 2013 +0200
    10.3 @@ -0,0 +1,67 @@
    10.4 +#include <stdio.h>
    10.5 +#include <set>
    10.6 +#include <string>
    10.7 +#include "logger.h"
    10.8 +#include "datapath.h"
    10.9 +
   10.10 +static std::set<std::string> paths;
   10.11 +
   10.12 +void add_data_path(const char *path)
   10.13 +{
   10.14 +	paths.insert(path);
   10.15 +}
   10.16 +
   10.17 +#ifndef TARGET_IPHONE
   10.18 +std::string datafile_path(const char *fname)
   10.19 +{
   10.20 +	std::string res;
   10.21 +	if(!fname) {
   10.22 +		return res;
   10.23 +	}
   10.24 +
   10.25 +	std::set<std::string>::const_iterator it = paths.begin();
   10.26 +	while(it != paths.end()) {
   10.27 +		const std::string &path = *it++;
   10.28 +		res = path + "/" + std::string(fname);
   10.29 +		FILE *fp = fopen(res.c_str(), "r");
   10.30 +		if(fp) {
   10.31 +			fclose(fp);
   10.32 +			return res;
   10.33 +		}
   10.34 +	}
   10.35 +
   10.36 +	// It's not found. Return the name itself just in case it's right here
   10.37 +	return std::string(fname);
   10.38 +}
   10.39 +#else
   10.40 +#include <CoreFoundation/CoreFoundation.h>
   10.41 +
   10.42 +std::string datafile_path(const char *fname)
   10.43 +{
   10.44 +	std::string res;
   10.45 +	if(!fname) {
   10.46 +		return res;
   10.47 +	}
   10.48 +
   10.49 +	CFBundleRef bundle;
   10.50 +	CFURLRef url;
   10.51 +	CFStringRef cfname;
   10.52 +
   10.53 +	cfname = CFStringCreateWithCString(0, fname, kCFStringEncodingASCII);
   10.54 +
   10.55 +	bundle = CFBundleGetMainBundle();
   10.56 +	if(!(url = CFBundleCopyResourceURL(bundle, cfname, 0, 0))) {
   10.57 +		CFRelease(cfname);
   10.58 +		return fname;
   10.59 +	}
   10.60 +	CFRelease(cfname);
   10.61 +
   10.62 +	char path[1024];
   10.63 +	if(!CFURLGetFileSystemRepresentation(url, 1, (unsigned char*)path, sizeof path)) {
   10.64 +		CFRelease(url);
   10.65 +		return fname;
   10.66 +	}
   10.67 +	CFRelease(url);
   10.68 +	return std::string(path);
   10.69 +}
   10.70 +#endif
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/datapath.h	Thu Nov 14 05:27:09 2013 +0200
    11.3 @@ -0,0 +1,10 @@
    11.4 +#ifndef DATAPATH_H_
    11.5 +#define DATAPATH_H_
    11.6 +
    11.7 +#include <string>
    11.8 +
    11.9 +void add_data_path(const char *path);
   11.10 +
   11.11 +std::string datafile_path(const char *fname);
   11.12 +
   11.13 +#endif	// DATAPATH_H_
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/dataset.h	Thu Nov 14 05:27:09 2013 +0200
    12.3 @@ -0,0 +1,44 @@
    12.4 +/** DataSet is a generic resource database with fast O(logn) lookups by name
    12.5 + * it can be used for texture managers, mesh managers, sound effect managers etc
    12.6 + *
    12.7 + * The constructor takes a load function and a destructor function to be called
    12.8 + * when a nonexistent resource is requested and needs to be loaded, and when
    12.9 + * the DataSet is destroyed. The destructor is optional and can be set to null
   12.10 + * if not needed.
   12.11 + *
   12.12 + * Requesting a resource works by simply calling get, example:
   12.13 + * ----------------------------------------------------------
   12.14 + * \code
   12.15 + * Texture *load_texture(const char *fname);
   12.16 + * void free_texture(Texture *tex);
   12.17 + *
   12.18 + * DataSet<Texture*> texman(load_texture, free_texture);
   12.19 + * Texture *foo = texman.get("foo.png");
   12.20 + * \endcode
   12.21 + */
   12.22 +#ifndef DATASET_H_
   12.23 +#define DATASET_H_
   12.24 +
   12.25 +#include <string>
   12.26 +#include <map>
   12.27 +
   12.28 +template <typename T>
   12.29 +class DataSet {
   12.30 +protected:
   12.31 +	mutable std::map<std::string, T> data;
   12.32 +
   12.33 +	T (*load)(const char*);
   12.34 +	void (*destroy)(T);
   12.35 +
   12.36 +public:
   12.37 +	DataSet(T (*load_func)(const char*), void (*destr_func)(T) = 0);
   12.38 +	~DataSet();
   12.39 +
   12.40 +	void clear();
   12.41 +
   12.42 +	T get(const char *name) const;
   12.43 +};
   12.44 +
   12.45 +#include "dataset.inl"
   12.46 +
   12.47 +#endif	// DATASET_H_
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/dataset.inl	Thu Nov 14 05:27:09 2013 +0200
    13.3 @@ -0,0 +1,56 @@
    13.4 +#include <stdio.h>
    13.5 +#include <string.h>
    13.6 +#include "datapath.h"
    13.7 +
    13.8 +template <typename T>
    13.9 +DataSet<T>::DataSet(T (*load_func)(const char*), void (*destr_func)(T))
   13.10 +{
   13.11 +	load = load_func;
   13.12 +	destroy = destr_func;
   13.13 +}
   13.14 +
   13.15 +template <typename T>
   13.16 +DataSet<T>::~DataSet()
   13.17 +{
   13.18 +	clear();
   13.19 +}
   13.20 +
   13.21 +template <typename T>
   13.22 +void DataSet<T>::clear()
   13.23 +{
   13.24 +	if(destroy) {
   13.25 +		typename std::map<std::string, T>::iterator it = data.begin();
   13.26 +		while(it != data.end()) {
   13.27 +			destroy(it++->second);
   13.28 +		}
   13.29 +	}
   13.30 +	data.clear();
   13.31 +}
   13.32 +
   13.33 +template <typename T>
   13.34 +T DataSet<T>::get(const char *name) const
   13.35 +{
   13.36 +	typename std::map<std::string, T>::const_iterator iter = data.find(name);
   13.37 +	if(iter != data.end()) {
   13.38 +		return iter->second;
   13.39 +	}
   13.40 +
   13.41 +	const char *fname, *slash;
   13.42 +	if((slash = strrchr(name, '/'))) {
   13.43 +		fname = slash + 1;
   13.44 +	} else {
   13.45 +		fname = name;
   13.46 +	}
   13.47 +
   13.48 +	std::string path = datafile_path(fname);
   13.49 +	if(path.empty()) {
   13.50 +		fprintf(stderr, "can't find data file: %s\n", name);
   13.51 +		return 0;
   13.52 +	}
   13.53 +
   13.54 +	T res = load(path.c_str());
   13.55 +	if(res) {
   13.56 +		data[name] = res;
   13.57 +	}
   13.58 +	return res;
   13.59 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/geom.cc	Thu Nov 14 05:27:09 2013 +0200
    14.3 @@ -0,0 +1,252 @@
    14.4 +#include <algorithm>
    14.5 +#include <float.h>
    14.6 +#include "geom.h"
    14.7 +#include "logger.h"
    14.8 +
    14.9 +GeomObject::~GeomObject()
   14.10 +{
   14.11 +}
   14.12 +
   14.13 +
   14.14 +Sphere::Sphere()
   14.15 +{
   14.16 +	radius = 1.0;
   14.17 +}
   14.18 +
   14.19 +Sphere::Sphere(const Vector3 &cent, float radius)
   14.20 +	: center(cent)
   14.21 +{
   14.22 +	this->radius = radius;
   14.23 +}
   14.24 +
   14.25 +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2)
   14.26 +{
   14.27 +	const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1);
   14.28 +	const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2);
   14.29 +
   14.30 +	if(!sph1 || !sph2) {
   14.31 +		error_log("Sphere::set_union: arguments must be spheres");
   14.32 +		return;
   14.33 +	}
   14.34 +
   14.35 +	float dist = (sph1->center - sph2->center).length();
   14.36 +	float surf_dist = dist - (sph1->radius + sph2->radius);
   14.37 +	float d1 = sph1->radius + surf_dist / 2.0;
   14.38 +	float d2 = sph2->radius + surf_dist / 2.0;
   14.39 +	float t = d1 / (d1 + d2);
   14.40 +
   14.41 +	if(t < 0.0) t = 0.0;
   14.42 +	if(t > 1.0) t = 1.0;
   14.43 +
   14.44 +	center = sph1->center * t + sph2->center * (1.0 - t);
   14.45 +	radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius);
   14.46 +}
   14.47 +
   14.48 +void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   14.49 +{
   14.50 +	error_log("Sphere::intersection undefined\n");
   14.51 +}
   14.52 +
   14.53 +bool Sphere::intersect(const Ray &ray, HitPoint *hit) const
   14.54 +{
   14.55 +	float a = dot_product(ray.dir, ray.dir);
   14.56 +	float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) +
   14.57 +		2.0 * ray.dir.y * (ray.origin.y - center.y) +
   14.58 +		2.0 * ray.dir.z * (ray.origin.z - center.z);
   14.59 +	float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) -
   14.60 +		2.0 * dot_product(ray.origin, center) - radius * radius;
   14.61 +
   14.62 +	float discr = b * b - 4.0 * a * c;
   14.63 +	if(discr < 1e-4) {
   14.64 +		return false;
   14.65 +	}
   14.66 +
   14.67 +	float sqrt_discr = sqrt(discr);
   14.68 +	float t0 = (-b + sqrt_discr) / (2.0 * a);
   14.69 +	float t1 = (-b - sqrt_discr) / (2.0 * a);
   14.70 +
   14.71 +	if(t0 < 1e-4)
   14.72 +		t0 = t1;
   14.73 +	if(t1 < 1e-4)
   14.74 +		t1 = t0;
   14.75 +
   14.76 +	float t = t0 < t1 ? t0 : t1;
   14.77 +	if(t < 1e-4) {
   14.78 +		return false;
   14.79 +	}
   14.80 +
   14.81 +	// fill the HitPoint structure
   14.82 +	if(hit) {
   14.83 +		hit->obj = this;
   14.84 +		hit->dist = t;
   14.85 +		hit->pos = ray.origin + ray.dir * t;
   14.86 +		hit->normal = (hit->pos - center) / radius;
   14.87 +	}
   14.88 +	return true;
   14.89 +}
   14.90 +
   14.91 +
   14.92 +AABox::AABox()
   14.93 +{
   14.94 +}
   14.95 +
   14.96 +AABox::AABox(const Vector3 &vmin, const Vector3 &vmax)
   14.97 +	: min(vmin), max(vmax)
   14.98 +{
   14.99 +}
  14.100 +
  14.101 +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2)
  14.102 +{
  14.103 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
  14.104 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
  14.105 +
  14.106 +	if(!box1 || !box2) {
  14.107 +		error_log("AABox::set_union: arguments must be AABoxes too\n");
  14.108 +		return;
  14.109 +	}
  14.110 +
  14.111 +	min.x = std::min(box1->min.x, box2->min.x);
  14.112 +	min.y = std::min(box1->min.y, box2->min.y);
  14.113 +	min.z = std::min(box1->min.z, box2->min.z);
  14.114 +
  14.115 +	max.x = std::max(box1->max.x, box2->max.x);
  14.116 +	max.y = std::max(box1->max.y, box2->max.y);
  14.117 +	max.z = std::max(box1->max.z, box2->max.z);
  14.118 +}
  14.119 +
  14.120 +void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
  14.121 +{
  14.122 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
  14.123 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
  14.124 +
  14.125 +	if(!box1 || !box2) {
  14.126 +		error_log("AABox::set_intersection: arguments must be AABoxes too\n");
  14.127 +		return;
  14.128 +	}
  14.129 +
  14.130 +	for(int i=0; i<3; i++) {
  14.131 +		min[i] = std::max(box1->min[i], box2->min[i]);
  14.132 +		max[i] = std::min(box1->max[i], box2->max[i]);
  14.133 +
  14.134 +		if(max[i] < min[i]) {
  14.135 +			max[i] = min[i];
  14.136 +		}
  14.137 +	}
  14.138 +}
  14.139 +
  14.140 +bool AABox::intersect(const Ray &ray, HitPoint *hit) const
  14.141 +{
  14.142 +	Vector3 param[2] = {min, max};
  14.143 +	Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
  14.144 +	int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
  14.145 +
  14.146 +	float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
  14.147 +	float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
  14.148 +	float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
  14.149 +	float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
  14.150 +
  14.151 +	if(tmin > tymax || tymin > tmax) {
  14.152 +		return false;
  14.153 +	}
  14.154 +	if(tymin > tmin) {
  14.155 +		tmin = tymin;
  14.156 +	}
  14.157 +	if(tymax < tmax) {
  14.158 +		tmax = tymax;
  14.159 +	}
  14.160 +
  14.161 +	float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
  14.162 +	float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
  14.163 +
  14.164 +	if(tmin > tzmax || tzmin > tmax) {
  14.165 +		return false;
  14.166 +	}
  14.167 +	if(tzmin > tmin) {
  14.168 +		tmin = tzmin;
  14.169 +	}
  14.170 +	if(tzmax < tmax) {
  14.171 +		tmax = tzmax;
  14.172 +	}
  14.173 +
  14.174 +	float t = tmin < 1e-4 ? tmax : tmin;
  14.175 +	if(t >= 1e-4) {
  14.176 +
  14.177 +		if(hit) {
  14.178 +			hit->obj = this;
  14.179 +			hit->dist = t;
  14.180 +			hit->pos = ray.origin + ray.dir * t;
  14.181 +
  14.182 +			float min_dist = FLT_MAX;
  14.183 +			Vector3 offs = min + (max - min) / 2.0;
  14.184 +			Vector3 local_hit = hit->pos - offs;
  14.185 +
  14.186 +			static const Vector3 axis[] = {
  14.187 +				Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)
  14.188 +			};
  14.189 +			//int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}};
  14.190 +
  14.191 +			for(int i=0; i<3; i++) {
  14.192 +				float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i]));
  14.193 +				if(dist < min_dist) {
  14.194 +					min_dist = dist;
  14.195 +					hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0);
  14.196 +					//hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]);
  14.197 +				}
  14.198 +			}
  14.199 +		}
  14.200 +		return true;
  14.201 +	}
  14.202 +	return false;
  14.203 +
  14.204 +}
  14.205 +
  14.206 +Plane::Plane()
  14.207 +	: normal(0.0, 1.0, 0.0)
  14.208 +{
  14.209 +}
  14.210 +
  14.211 +Plane::Plane(const Vector3 &p, const Vector3 &norm)
  14.212 +	: pt(p)
  14.213 +{
  14.214 +	normal = norm.normalized();
  14.215 +}
  14.216 +
  14.217 +Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3)
  14.218 +	: pt(p1)
  14.219 +{
  14.220 +	normal = cross_product(p2 - p1, p3 - p1).normalized();
  14.221 +}
  14.222 +
  14.223 +Plane::Plane(const Vector3 &normal, float dist)
  14.224 +{
  14.225 +	this->normal = normal.normalized();
  14.226 +	pt = this->normal * dist;
  14.227 +}
  14.228 +
  14.229 +void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2)
  14.230 +{
  14.231 +	error_log("Plane::set_union undefined\n");
  14.232 +}
  14.233 +
  14.234 +void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
  14.235 +{
  14.236 +	error_log("Plane::set_intersection undefined\n");
  14.237 +}
  14.238 +
  14.239 +bool Plane::intersect(const Ray &ray, HitPoint *hit) const
  14.240 +{
  14.241 +	float ndotdir = dot_product(normal, ray.dir);
  14.242 +	if(fabs(ndotdir) < 1e-4) {
  14.243 +		return false;
  14.244 +	}
  14.245 +
  14.246 +	if(hit) {
  14.247 +		Vector3 ptdir = pt - ray.origin;
  14.248 +		float t = dot_product(normal, ptdir) / ndotdir;
  14.249 +
  14.250 +		hit->pos = ray.origin + ray.dir * t;
  14.251 +		hit->normal = normal;
  14.252 +		hit->obj = this;
  14.253 +	}
  14.254 +	return true;
  14.255 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/geom.h	Thu Nov 14 05:27:09 2013 +0200
    15.3 @@ -0,0 +1,67 @@
    15.4 +#ifndef GEOMOBJ_H_
    15.5 +#define GEOMOBJ_H_
    15.6 +
    15.7 +#include "vmath/vmath.h"
    15.8 +
    15.9 +class GeomObject;
   15.10 +
   15.11 +struct HitPoint {
   15.12 +	float dist;				//< parametric distance along the ray
   15.13 +	Vector3 pos;			//< position of intersection (orig + dir * dist)
   15.14 +	Vector3 normal;			//< normal at the point of intersection
   15.15 +	const void *obj;		//< pointer to the intersected object
   15.16 +};
   15.17 +
   15.18 +class GeomObject {
   15.19 +public:
   15.20 +	virtual ~GeomObject();
   15.21 +
   15.22 +	virtual void set_union(const GeomObject *obj1, const GeomObject *obj2) = 0;
   15.23 +	virtual void set_intersection(const GeomObject *obj1, const GeomObject *obj2) = 0;
   15.24 +
   15.25 +	virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0;
   15.26 +};
   15.27 +
   15.28 +class Sphere : public GeomObject {
   15.29 +public:
   15.30 +	Vector3 center;
   15.31 +	float radius;
   15.32 +
   15.33 +	Sphere();
   15.34 +	Sphere(const Vector3 &center, float radius);
   15.35 +
   15.36 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
   15.37 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
   15.38 +
   15.39 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   15.40 +};
   15.41 +
   15.42 +class AABox : public GeomObject {
   15.43 +public:
   15.44 +	Vector3 min, max;
   15.45 +
   15.46 +	AABox();
   15.47 +	AABox(const Vector3 &min, const Vector3 &max);
   15.48 +
   15.49 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
   15.50 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
   15.51 +
   15.52 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   15.53 +};
   15.54 +
   15.55 +class Plane : public GeomObject {
   15.56 +public:
   15.57 +	Vector3 pt, normal;
   15.58 +
   15.59 +	Plane();
   15.60 +	Plane(const Vector3 &pt, const Vector3 &normal);
   15.61 +	Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3);
   15.62 +	Plane(const Vector3 &normal, float dist);
   15.63 +
   15.64 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
   15.65 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
   15.66 +
   15.67 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   15.68 +};
   15.69 +
   15.70 +#endif	// GEOMOBJ_H_
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/gfxutil.cc	Thu Nov 14 05:27:09 2013 +0200
    16.3 @@ -0,0 +1,64 @@
    16.4 +#include <assert.h>
    16.5 +#include "gfxutil.h"
    16.6 +#include "mesh.h"
    16.7 +#include "meshgen.h"
    16.8 +#include "texture.h"
    16.9 +#include "shader.h"
   16.10 +#include "sdrman.h"
   16.11 +#include "opengl.h"
   16.12 +#include "logger.h"
   16.13 +
   16.14 +void draw_rect(const Vector3 &v1, const Vector3 &v2, Texture2D *tex, ShaderProg *sdr)
   16.15 +{
   16.16 +	static ShaderProg *defsdr;
   16.17 +
   16.18 +	if(!defsdr) {
   16.19 +		if(!(defsdr = get_sdrprog("defpost.v.glsl", "defpost.p.glsl"))) {
   16.20 +			static bool didlog;
   16.21 +			if(!didlog) {
   16.22 +				error_log("draw_rect: failed to load default shader\n");
   16.23 +				didlog = true;
   16.24 +			}
   16.25 +			if(!sdr) {
   16.26 +				return;
   16.27 +			}
   16.28 +		}
   16.29 +	}
   16.30 +
   16.31 +
   16.32 +	if(tex) {
   16.33 +		set_texture(tex);
   16.34 +	}
   16.35 +	if(sdr) {
   16.36 +		sdr->bind();
   16.37 +	} else {
   16.38 +		defsdr->bind();
   16.39 +
   16.40 +		assert(defsdr->get_attrib_location("attr_vertex") == MESH_ATTR_VERTEX);
   16.41 +		assert(defsdr->get_attrib_location("attr_texcoord") == MESH_ATTR_TEXCOORD);
   16.42 +	}
   16.43 +
   16.44 +
   16.45 +	float varr[] = {
   16.46 +		v1.x, v1.y, v1.z, v2.x, v1.y, v2.z,
   16.47 +		v2.x, v2.y, v2.z, v1.x, v2.y, v1.z
   16.48 +	};
   16.49 +	static const float tarr[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
   16.50 +	static const unsigned int idxarr[] = {0, 1, 2, 0, 2, 3};
   16.51 +
   16.52 +	// disable VBOs if they are enabled
   16.53 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
   16.54 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
   16.55 +
   16.56 +	glEnableVertexAttribArray(MESH_ATTR_VERTEX);
   16.57 +	glVertexAttribPointer(MESH_ATTR_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, varr);
   16.58 +	glEnableVertexAttribArray(MESH_ATTR_TEXCOORD);
   16.59 +	glVertexAttribPointer(MESH_ATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, tarr);
   16.60 +
   16.61 +	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, idxarr);
   16.62 +
   16.63 +	glDisableVertexAttribArray(MESH_ATTR_VERTEX);
   16.64 +	glDisableVertexAttribArray(MESH_ATTR_TEXCOORD);
   16.65 +
   16.66 +	set_texture(0);
   16.67 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/gfxutil.h	Thu Nov 14 05:27:09 2013 +0200
    17.3 @@ -0,0 +1,11 @@
    17.4 +#ifndef GFXUTIL_H_
    17.5 +#define GFXUTIL_H_
    17.6 +
    17.7 +#include <vmath/vmath.h>
    17.8 +
    17.9 +class Texture2D;
   17.10 +class ShaderProg;
   17.11 +
   17.12 +void draw_rect(const Vector3 &v1, const Vector3 &v2, Texture2D *tex = 0, ShaderProg *sdr = 0);
   17.13 +
   17.14 +#endif	// GFXUTIL_H_
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/image.cc	Thu Nov 14 05:27:09 2013 +0200
    18.3 @@ -0,0 +1,192 @@
    18.4 +#include <string.h>
    18.5 +#include "imago2.h"
    18.6 +#include "image.h"
    18.7 +#include "logger.h"
    18.8 +
    18.9 +
   18.10 +static int pixel_elements(Image::Format fmt);
   18.11 +static int elem_size(Image::Format fmt);
   18.12 +static int pixel_size(Image::Format fmt);
   18.13 +
   18.14 +Image::Image()
   18.15 +{
   18.16 +	fmt = FMT_RGBA;
   18.17 +	width = height = 0;
   18.18 +	pixels = 0;
   18.19 +}
   18.20 +
   18.21 +Image::~Image()
   18.22 +{
   18.23 +	delete [] (char*)pixels;
   18.24 +}
   18.25 +
   18.26 +int Image::get_width() const
   18.27 +{
   18.28 +	return width;
   18.29 +}
   18.30 +
   18.31 +int Image::get_height() const
   18.32 +{
   18.33 +	return height;
   18.34 +}
   18.35 +
   18.36 +Image::Format Image::get_format() const
   18.37 +{
   18.38 +	return fmt;
   18.39 +}
   18.40 +
   18.41 +bool Image::create(int x, int y, Format fmt)
   18.42 +{
   18.43 +	width = x;
   18.44 +	height = y;
   18.45 +	this->fmt = fmt;
   18.46 +
   18.47 +	try {
   18.48 +		pixels = new char[x * y * pixel_size(fmt)];
   18.49 +	}
   18.50 +	catch(...) {
   18.51 +		return false;
   18.52 +	}
   18.53 +	return true;
   18.54 +}
   18.55 +
   18.56 +bool Image::set_pixels(int x, int y, void *pixels, Format fmt)
   18.57 +{
   18.58 +	if(!create(x, y, fmt)) {
   18.59 +		return false;
   18.60 +	}
   18.61 +	memcpy(this->pixels, pixels, x * y * pixel_size(fmt));
   18.62 +	return true;
   18.63 +}
   18.64 +
   18.65 +void *Image::get_pixels() const
   18.66 +{
   18.67 +	return pixels;
   18.68 +}
   18.69 +
   18.70 +bool Image::load(const char *fname)
   18.71 +{
   18.72 +	struct img_pixmap pixmap;
   18.73 +
   18.74 +	img_init(&pixmap);
   18.75 +	if(img_load(&pixmap, fname) == -1) {
   18.76 +		return false;
   18.77 +	}
   18.78 +
   18.79 +	Format fmt;
   18.80 +	switch(pixmap.fmt) {
   18.81 +	case IMG_FMT_GREY8:
   18.82 +		fmt = FMT_GREY;
   18.83 +		break;
   18.84 +	case IMG_FMT_RGB24:
   18.85 +		fmt = FMT_RGB;
   18.86 +		break;
   18.87 +	case IMG_FMT_RGBA32:
   18.88 +		fmt = FMT_RGBA;
   18.89 +		break;
   18.90 +	case IMG_FMT_GREYF:
   18.91 +		fmt = FMT_GREY_FLOAT;
   18.92 +		break;
   18.93 +	case IMG_FMT_RGBF:
   18.94 +		fmt = FMT_RGB_FLOAT;
   18.95 +		break;
   18.96 +	case IMG_FMT_RGBAF:
   18.97 +		fmt = FMT_RGBA_FLOAT;
   18.98 +		break;
   18.99 +	default:
  18.100 +		img_destroy(&pixmap);
  18.101 +		return false;
  18.102 +	}
  18.103 +
  18.104 +	if(!set_pixels(pixmap.width, pixmap.height, pixmap.pixels, fmt)) {
  18.105 +		img_destroy(&pixmap);
  18.106 +		return false;
  18.107 +	}
  18.108 +	img_destroy(&pixmap);
  18.109 +	return true;
  18.110 +}
  18.111 +
  18.112 +bool Image::save(const char *fname) const
  18.113 +{
  18.114 +	struct img_pixmap pixmap;
  18.115 +
  18.116 +	img_init(&pixmap);
  18.117 +
  18.118 +	switch(fmt) {
  18.119 +	case FMT_GREY:
  18.120 +		pixmap.fmt = IMG_FMT_GREY8;
  18.121 +		break;
  18.122 +	case FMT_GREY_FLOAT:
  18.123 +		pixmap.fmt = IMG_FMT_GREYF;
  18.124 +		break;
  18.125 +	case FMT_RGB:
  18.126 +		pixmap.fmt = IMG_FMT_RGB24;
  18.127 +		break;
  18.128 +	case FMT_RGB_FLOAT:
  18.129 +		pixmap.fmt = IMG_FMT_RGBF;
  18.130 +		break;
  18.131 +	case FMT_RGBA:
  18.132 +		pixmap.fmt = IMG_FMT_RGBA32;
  18.133 +		break;
  18.134 +	case FMT_RGBA_FLOAT:
  18.135 +		pixmap.fmt = IMG_FMT_RGBAF;
  18.136 +		break;
  18.137 +	default:
  18.138 +		return false;
  18.139 +	}
  18.140 +
  18.141 +	pixmap.width = width;
  18.142 +	pixmap.height = height;
  18.143 +	pixmap.pixels = pixels;
  18.144 +	pixmap.pixelsz = pixel_size(fmt);
  18.145 +
  18.146 +	if(img_save(&pixmap, fname) == -1) {
  18.147 +		return false;
  18.148 +	}
  18.149 +	return true;
  18.150 +}
  18.151 +
  18.152 +static int pixel_elements(Image::Format fmt)
  18.153 +{
  18.154 +	switch(fmt) {
  18.155 +	case Image::FMT_GREY:
  18.156 +	case Image::FMT_GREY_FLOAT:
  18.157 +		return 1;
  18.158 +
  18.159 +	case Image::FMT_RGB:
  18.160 +	case Image::FMT_RGB_FLOAT:
  18.161 +		return 3;
  18.162 +
  18.163 +	case Image::FMT_RGBA:
  18.164 +	case Image::FMT_RGBA_FLOAT:
  18.165 +		return 4;
  18.166 +
  18.167 +	default:
  18.168 +		break;
  18.169 +	}
  18.170 +	return 0;
  18.171 +}
  18.172 +
  18.173 +static int elem_size(Image::Format fmt)
  18.174 +{
  18.175 +	switch(fmt) {
  18.176 +	case Image::FMT_GREY:
  18.177 +	case Image::FMT_RGB:
  18.178 +	case Image::FMT_RGBA:
  18.179 +		return 1;
  18.180 +
  18.181 +	case Image::FMT_GREY_FLOAT:
  18.182 +	case Image::FMT_RGB_FLOAT:
  18.183 +	case Image::FMT_RGBA_FLOAT:
  18.184 +		return sizeof(float);
  18.185 +
  18.186 +	default:
  18.187 +		break;
  18.188 +	}
  18.189 +	return 0;
  18.190 +}
  18.191 +
  18.192 +static int pixel_size(Image::Format fmt)
  18.193 +{
  18.194 +	return elem_size(fmt) * pixel_elements(fmt);
  18.195 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/image.h	Thu Nov 14 05:27:09 2013 +0200
    19.3 @@ -0,0 +1,38 @@
    19.4 +#ifndef IMAGE_H_
    19.5 +#define IMAGE_H_
    19.6 +
    19.7 +
    19.8 +class Image {
    19.9 +public:
   19.10 +	enum Format {
   19.11 +		FMT_GREY,
   19.12 +		FMT_RGB,
   19.13 +		FMT_RGBA,
   19.14 +		FMT_GREY_FLOAT,
   19.15 +		FMT_RGB_FLOAT,
   19.16 +		FMT_RGBA_FLOAT
   19.17 +	};
   19.18 +
   19.19 +private:
   19.20 +	Format fmt;
   19.21 +	int width, height;
   19.22 +	void *pixels;
   19.23 +
   19.24 +public:
   19.25 +	Image();
   19.26 +	~Image();
   19.27 +
   19.28 +	int get_width() const;
   19.29 +	int get_height() const;
   19.30 +
   19.31 +	Format get_format() const;
   19.32 +
   19.33 +	bool create(int x, int y, Format fmt = FMT_RGBA);
   19.34 +	bool set_pixels(int x, int y, void *pixels, Format fmt = FMT_RGBA);
   19.35 +	void *get_pixels() const;
   19.36 +
   19.37 +	bool load(const char *fname);
   19.38 +	bool save(const char *fname) const;
   19.39 +};
   19.40 +
   19.41 +#endif	// IMAGE_H_
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/logger.cc	Thu Nov 14 05:27:09 2013 +0200
    20.3 @@ -0,0 +1,96 @@
    20.4 +#include <stdio.h>
    20.5 +#include <stdarg.h>
    20.6 +#include "logger.h"
    20.7 +
    20.8 +#if defined(unix) || defined(__unix__) || defined(__APPLE__)
    20.9 +#include <unistd.h>
   20.10 +#endif
   20.11 +
   20.12 +enum { LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG };
   20.13 +
   20.14 +static int typecolor(int type);
   20.15 +
   20.16 +static FILE *fp = stdout;
   20.17 +
   20.18 +static void logmsg(int type, const char *fmt, va_list ap)
   20.19 +{
   20.20 +#if defined(unix) || defined(__unix__) || (defined(__APPLE__) && !defined(TARGET_IPHONE))
   20.21 +	if(isatty(fileno(fp)) && type != LOG_INFO) {
   20.22 +		int c = typecolor(type);
   20.23 +		fprintf(fp, "\033[%dm", c);
   20.24 +		vfprintf(fp, fmt, ap);
   20.25 +		fprintf(fp, "\033[0m");
   20.26 +	} else
   20.27 +#endif
   20.28 +	{
   20.29 +		vfprintf(fp, fmt, ap);
   20.30 +	}
   20.31 +	if(type == LOG_ERROR || type == LOG_DEBUG) {
   20.32 +		fflush(fp);
   20.33 +	}
   20.34 +}
   20.35 +
   20.36 +void info_log(const char *fmt, ...)
   20.37 +{
   20.38 +	va_list ap;
   20.39 +
   20.40 +	va_start(ap, fmt);
   20.41 +	logmsg(LOG_INFO, fmt, ap);
   20.42 +	va_end(ap);
   20.43 +}
   20.44 +
   20.45 +void warning_log(const char *fmt, ...)
   20.46 +{
   20.47 +	va_list ap;
   20.48 +
   20.49 +	va_start(ap, fmt);
   20.50 +	logmsg(LOG_WARNING, fmt, ap);
   20.51 +	va_end(ap);
   20.52 +}
   20.53 +
   20.54 +void error_log(const char *fmt, ...)
   20.55 +{
   20.56 +	va_list ap;
   20.57 +
   20.58 +	va_start(ap, fmt);
   20.59 +	logmsg(LOG_ERROR, fmt, ap);
   20.60 +	va_end(ap);
   20.61 +}
   20.62 +
   20.63 +void debug_log(const char *fmt, ...)
   20.64 +{
   20.65 +	va_list ap;
   20.66 +
   20.67 +	va_start(ap, fmt);
   20.68 +	logmsg(LOG_DEBUG, fmt, ap);
   20.69 +	va_end(ap);
   20.70 +}
   20.71 +
   20.72 +enum {
   20.73 +	BLACK = 0,
   20.74 +	RED,
   20.75 +	GREEN,
   20.76 +	YELLOW,
   20.77 +	BLUE,
   20.78 +	MAGENTA,
   20.79 +	CYAN,
   20.80 +	WHITE
   20.81 +};
   20.82 +
   20.83 +#define ANSI_FGCOLOR(x)	(30 + (x))
   20.84 +#define ANSI_BGCOLOR(x)	(40 + (x))
   20.85 +
   20.86 +static int typecolor(int type)
   20.87 +{
   20.88 +	switch(type) {
   20.89 +	case LOG_ERROR:
   20.90 +		return ANSI_FGCOLOR(RED);
   20.91 +	case LOG_WARNING:
   20.92 +		return ANSI_FGCOLOR(YELLOW);
   20.93 +	case LOG_DEBUG:
   20.94 +		return ANSI_FGCOLOR(MAGENTA);
   20.95 +	default:
   20.96 +		break;
   20.97 +	}
   20.98 +	return 37;
   20.99 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/src/logger.h	Thu Nov 14 05:27:09 2013 +0200
    21.3 @@ -0,0 +1,9 @@
    21.4 +#ifndef LOGGER_H_
    21.5 +#define LOGGER_H_
    21.6 +
    21.7 +void info_log(const char *fmt, ...);
    21.8 +void warning_log(const char *fmt, ...);
    21.9 +void error_log(const char *fmt, ...);
   21.10 +void debug_log(const char *fmt, ...);
   21.11 +
   21.12 +#endif	// LOGGER_H_
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/material.cc	Thu Nov 14 05:27:09 2013 +0200
    22.3 @@ -0,0 +1,65 @@
    22.4 +#include "material.h"
    22.5 +#include "unistate.h"
    22.6 +
    22.7 +Material::Material()
    22.8 +	: diffuse(1, 1, 1), specular(0, 0, 0)
    22.9 +{
   22.10 +	alpha = 1.0;
   22.11 +	shininess = 1.0;
   22.12 +
   22.13 +	for(int i=0; i<MAX_MTL_TEXTURES; i++) {
   22.14 +		tex[i] = 0;
   22.15 +	}
   22.16 +}
   22.17 +
   22.18 +
   22.19 +void Material::setup(bool use_textures) const
   22.20 +{
   22.21 +	static bool done_init;
   22.22 +	static int st_diffuse_idx, st_specular_idx, st_shininess_idx, st_alpha_idx;
   22.23 +	static int st_tex_diffuse_idx, st_tex_specular_idx, st_tex_normal_idx;
   22.24 +	static int st_tex_idx[MAX_MTL_TEXTURES];
   22.25 +
   22.26 +	if(!done_init) {
   22.27 +		st_diffuse_idx = add_unistate("st_mtl_diffuse", ST_FLOAT3);
   22.28 +		st_specular_idx = add_unistate("st_mtl_specular", ST_FLOAT3);
   22.29 +		st_shininess_idx = add_unistate("st_mtl_shininess", ST_FLOAT);
   22.30 +		st_alpha_idx = add_unistate("st_mtl_alpha", ST_FLOAT);
   22.31 +		st_tex_diffuse_idx = add_unistate("st_tex_diffuse", ST_INT);
   22.32 +		st_tex_specular_idx = add_unistate("st_tex_specular", ST_INT);
   22.33 +		st_tex_normal_idx = add_unistate("st_tex_normal", ST_INT);
   22.34 +
   22.35 +		for(int i=0; i<MAX_MTL_TEXTURES; i++) {
   22.36 +			char name[32];
   22.37 +			sprintf(name, "st_tex%d", i);
   22.38 +			st_tex_idx[i] = add_unistate(name, ST_INT);
   22.39 +		}
   22.40 +		done_init = true;
   22.41 +	}
   22.42 +
   22.43 +	set_unistate(st_diffuse_idx, diffuse);
   22.44 +	set_unistate(st_specular_idx, specular);
   22.45 +	set_unistate(st_shininess_idx, shininess);
   22.46 +	set_unistate(st_alpha_idx, alpha);
   22.47 +
   22.48 +	if(!use_textures) {
   22.49 +		return;	// we're done
   22.50 +	}
   22.51 +
   22.52 +	const int tex_named_idx[] = {
   22.53 +		st_tex_diffuse_idx, st_tex_specular_idx, st_tex_normal_idx, -1
   22.54 +	};
   22.55 +
   22.56 +	int tex_unit = 0;
   22.57 +	for(int i=0; i<MAX_MTL_TEXTURES; i++) {
   22.58 +		if(tex[i]) {
   22.59 +			tex[i]->bind(tex_unit);
   22.60 +
   22.61 +			if(tex_named_idx[i]) {
   22.62 +				set_unistate(tex_named_idx[i], tex_unit);
   22.63 +			}
   22.64 +			set_unistate(st_tex_idx[i], tex_unit);
   22.65 +			tex_unit++;
   22.66 +		}
   22.67 +	}
   22.68 +}
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/src/material.h	Thu Nov 14 05:27:09 2013 +0200
    23.3 @@ -0,0 +1,29 @@
    23.4 +#ifndef MATERIAL_H_
    23.5 +#define MATERIAL_H_
    23.6 +
    23.7 +#include "vmath/vmath.h"
    23.8 +#include "texture.h"
    23.9 +
   23.10 +enum {
   23.11 +	TEX_DIFFUSE,
   23.12 +	TEX_SPECULAR,
   23.13 +	TEX_NORMAL,
   23.14 +	TEX_MISC,
   23.15 +
   23.16 +	MAX_MTL_TEXTURES
   23.17 +};
   23.18 +
   23.19 +class Material {
   23.20 +public:
   23.21 +	Vector3 diffuse, specular;
   23.22 +	float alpha;
   23.23 +	float shininess;
   23.24 +
   23.25 +	Texture *tex[MAX_MTL_TEXTURES];
   23.26 +
   23.27 +	Material();
   23.28 +
   23.29 +	void setup(bool use_textures = true) const;
   23.30 +};
   23.31 +
   23.32 +#endif	// MATERIAL_H_
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/mesh.cc	Thu Nov 14 05:27:09 2013 +0200
    24.3 @@ -0,0 +1,971 @@
    24.4 +#include <stdio.h>
    24.5 +#include <stdlib.h>
    24.6 +#include <float.h>
    24.7 +#include <assert.h>
    24.8 +#include "opengl.h"
    24.9 +#include "mesh.h"
   24.10 +#include "xform_node.h"
   24.11 +#include "logger.h"
   24.12 +
   24.13 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5 };
   24.14 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
   24.15 +float Mesh::vertex_sel_dist = 0.01;
   24.16 +float Mesh::vis_vecsize = 1.0;
   24.17 +
   24.18 +Mesh::Mesh()
   24.19 +{
   24.20 +	clear();
   24.21 +
   24.22 +	glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   24.23 +
   24.24 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   24.25 +		vattr[i].vbo = buffer_objects[i];
   24.26 +	}
   24.27 +	ibo = buffer_objects[NUM_MESH_ATTR];
   24.28 +	wire_ibo = 0;
   24.29 +}
   24.30 +
   24.31 +Mesh::~Mesh()
   24.32 +{
   24.33 +	glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   24.34 +
   24.35 +	if(wire_ibo) {
   24.36 +		glDeleteBuffers(1, &wire_ibo);
   24.37 +	}
   24.38 +}
   24.39 +
   24.40 +void Mesh::set_name(const char *name)
   24.41 +{
   24.42 +	this->name = name;
   24.43 +}
   24.44 +
   24.45 +const char *Mesh::get_name() const
   24.46 +{
   24.47 +	return name.c_str();
   24.48 +}
   24.49 +
   24.50 +bool Mesh::has_attrib(int attr) const
   24.51 +{
   24.52 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
   24.53 +		return false;
   24.54 +	}
   24.55 +
   24.56 +	// if neither of these is valid, then nobody has set this attribute
   24.57 +	return vattr[attr].vbo_valid || vattr[attr].data_valid;
   24.58 +}
   24.59 +
   24.60 +void Mesh::clear()
   24.61 +{
   24.62 +	bones.clear();
   24.63 +
   24.64 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   24.65 +		vattr[i].nelem = 0;
   24.66 +		vattr[i].vbo_valid = false;
   24.67 +		vattr[i].data_valid = false;
   24.68 +		//vattr[i].sdr_loc = -1;
   24.69 +		vattr[i].data.clear();
   24.70 +	}
   24.71 +	ibo_valid = false;
   24.72 +	idata.clear();
   24.73 +
   24.74 +	wire_ibo_valid = false;
   24.75 +
   24.76 +	nverts = nfaces = 0;
   24.77 +
   24.78 +	bsph_valid = false;
   24.79 +	aabb_valid = false;
   24.80 +}
   24.81 +
   24.82 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
   24.83 +{
   24.84 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
   24.85 +		error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
   24.86 +		return 0;
   24.87 +	}
   24.88 +
   24.89 +	if(nverts && num != nverts) {
   24.90 +		error_log("%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
   24.91 +		return 0;
   24.92 +	}
   24.93 +	nverts = num;
   24.94 +
   24.95 +	vattr[attrib].data.clear();
   24.96 +	vattr[attrib].nelem = nelem;
   24.97 +	vattr[attrib].data.resize(num * nelem);
   24.98 +
   24.99 +	if(data) {
  24.100 +		memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
  24.101 +	}
  24.102 +
  24.103 +	vattr[attrib].data_valid = true;
  24.104 +	vattr[attrib].vbo_valid = false;
  24.105 +	return &vattr[attrib].data[0];
  24.106 +}
  24.107 +
  24.108 +float *Mesh::get_attrib_data(int attrib)
  24.109 +{
  24.110 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  24.111 +		error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  24.112 +		return 0;
  24.113 +	}
  24.114 +
  24.115 +	vattr[attrib].vbo_valid = false;
  24.116 +	return (float*)((const Mesh*)this)->get_attrib_data(attrib);
  24.117 +}
  24.118 +
  24.119 +const float *Mesh::get_attrib_data(int attrib) const
  24.120 +{
  24.121 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  24.122 +		error_log("%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  24.123 +		return 0;
  24.124 +	}
  24.125 +
  24.126 +	if(!vattr[attrib].data_valid) {
  24.127 +#if GL_ES_VERSION_2_0
  24.128 +		error_log("%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
  24.129 +		return 0;
  24.130 +#else
  24.131 +		if(!vattr[attrib].vbo_valid) {
  24.132 +			error_log("%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
  24.133 +			return 0;
  24.134 +		}
  24.135 +
  24.136 +		// local data copy is unavailable, grab the data from the vbo
  24.137 +		Mesh *m = (Mesh*)this;
  24.138 +		m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
  24.139 +
  24.140 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
  24.141 +		void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
  24.142 +		memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
  24.143 +		glUnmapBuffer(GL_ARRAY_BUFFER);
  24.144 +
  24.145 +		vattr[attrib].data_valid = true;
  24.146 +#endif
  24.147 +	}
  24.148 +
  24.149 +	return &vattr[attrib].data[0];
  24.150 +}
  24.151 +
  24.152 +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
  24.153 +{
  24.154 +	float *data = get_attrib_data(attrib);
  24.155 +	if(data) {
  24.156 +		data += idx * vattr[attrib].nelem;
  24.157 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  24.158 +			data[i] = v[i];
  24.159 +		}
  24.160 +	}
  24.161 +}
  24.162 +
  24.163 +Vector4 Mesh::get_attrib(int attrib, int idx) const
  24.164 +{
  24.165 +	Vector4 v(0.0, 0.0, 0.0, 1.0);
  24.166 +	const float *data = get_attrib_data(attrib);
  24.167 +	if(data) {
  24.168 +		data += idx * vattr[attrib].nelem;
  24.169 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  24.170 +			v[i] = data[i];
  24.171 +		}
  24.172 +	}
  24.173 +	return v;
  24.174 +}
  24.175 +
  24.176 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
  24.177 +{
  24.178 +	int nidx = nfaces * 3;
  24.179 +	if(nidx && num != nidx) {
  24.180 +		error_log("%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
  24.181 +		return 0;
  24.182 +	}
  24.183 +	nfaces = num / 3;
  24.184 +
  24.185 +	idata.clear();
  24.186 +	idata.resize(num);
  24.187 +
  24.188 +	if(indices) {
  24.189 +		memcpy(&idata[0], indices, num * sizeof *indices);
  24.190 +	}
  24.191 +
  24.192 +	idata_valid = true;
  24.193 +	ibo_valid = false;
  24.194 +
  24.195 +	return &idata[0];
  24.196 +}
  24.197 +
  24.198 +unsigned int *Mesh::get_index_data()
  24.199 +{
  24.200 +	ibo_valid = false;
  24.201 +	return (unsigned int*)((const Mesh*)this)->get_index_data();
  24.202 +}
  24.203 +
  24.204 +const unsigned int *Mesh::get_index_data() const
  24.205 +{
  24.206 +	if(!idata_valid) {
  24.207 +#if GL_ES_VERSION_2_0
  24.208 +		error_log("%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
  24.209 +		return 0;
  24.210 +#else
  24.211 +		if(!ibo_valid) {
  24.212 +			error_log("%s: indices unavailable\n", __FUNCTION__);
  24.213 +			return 0;
  24.214 +		}
  24.215 +
  24.216 +		// local data copy is unavailable, gram the data from the ibo
  24.217 +		Mesh *m = (Mesh*)this;
  24.218 +		int nidx = nfaces * 3;
  24.219 +		m->idata.resize(nidx);
  24.220 +
  24.221 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  24.222 +		void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
  24.223 +		memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
  24.224 +		glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
  24.225 +
  24.226 +		idata_valid = true;
  24.227 +#endif
  24.228 +	}
  24.229 +
  24.230 +	return &idata[0];
  24.231 +}
  24.232 +
  24.233 +void Mesh::append(const Mesh &mesh)
  24.234 +{
  24.235 +	unsigned int idxoffs = nverts;
  24.236 +
  24.237 +	nverts += mesh.nverts;
  24.238 +	nfaces += mesh.nfaces;
  24.239 +
  24.240 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.241 +		if(has_attrib(i) && mesh.has_attrib(i)) {
  24.242 +			// force validating the data arrays
  24.243 +			get_attrib_data(i);
  24.244 +			mesh.get_attrib_data(i);
  24.245 +
  24.246 +			// append the mesh data
  24.247 +			vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
  24.248 +		}
  24.249 +	}
  24.250 +
  24.251 +	if(ibo_valid || idata_valid) {
  24.252 +		// make index arrays valid
  24.253 +		get_index_data();
  24.254 +		mesh.get_index_data();
  24.255 +
  24.256 +		size_t orig_sz = idata.size();
  24.257 +
  24.258 +		idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
  24.259 +
  24.260 +		// fixup all the new indices
  24.261 +		for(size_t i=orig_sz; i<idata.size(); i++) {
  24.262 +			idata[i] += idxoffs;
  24.263 +		}
  24.264 +	}
  24.265 +
  24.266 +	// fuck everything
  24.267 +	wire_ibo_valid = false;
  24.268 +	aabb_valid = false;
  24.269 +	bsph_valid = false;
  24.270 +}
  24.271 +
  24.272 +// assemble a complete vertex by adding all the useful attributes
  24.273 +void Mesh::vertex(float x, float y, float z)
  24.274 +{
  24.275 +	cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
  24.276 +	vattr[MESH_ATTR_VERTEX].data_valid = true;
  24.277 +	vattr[MESH_ATTR_VERTEX].nelem = 3;
  24.278 +
  24.279 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.280 +		if(vattr[i].data_valid) {
  24.281 +			for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
  24.282 +				vattr[i].data.push_back(cur_val[i][j]);
  24.283 +			}
  24.284 +		}
  24.285 +		vattr[i].vbo_valid = false;
  24.286 +	}
  24.287 +
  24.288 +	if(idata_valid) {
  24.289 +		idata.clear();
  24.290 +	}
  24.291 +	ibo_valid = idata_valid = false;
  24.292 +}
  24.293 +
  24.294 +void Mesh::normal(float nx, float ny, float nz)
  24.295 +{
  24.296 +	cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
  24.297 +	vattr[MESH_ATTR_NORMAL].data_valid = true;
  24.298 +	vattr[MESH_ATTR_NORMAL].nelem = 3;
  24.299 +}
  24.300 +
  24.301 +void Mesh::tangent(float tx, float ty, float tz)
  24.302 +{
  24.303 +	cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
  24.304 +	vattr[MESH_ATTR_TANGENT].data_valid = true;
  24.305 +	vattr[MESH_ATTR_TANGENT].nelem = 3;
  24.306 +}
  24.307 +
  24.308 +void Mesh::texcoord(float u, float v, float w)
  24.309 +{
  24.310 +	cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
  24.311 +	vattr[MESH_ATTR_TEXCOORD].data_valid = true;
  24.312 +	vattr[MESH_ATTR_TEXCOORD].nelem = 3;
  24.313 +}
  24.314 +
  24.315 +void Mesh::boneweights(float w1, float w2, float w3, float w4)
  24.316 +{
  24.317 +	cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
  24.318 +	vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
  24.319 +	vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
  24.320 +}
  24.321 +
  24.322 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
  24.323 +{
  24.324 +	cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
  24.325 +	vattr[MESH_ATTR_BONEIDX].data_valid = true;
  24.326 +	vattr[MESH_ATTR_BONEIDX].nelem = 4;
  24.327 +}
  24.328 +
  24.329 +/// static function
  24.330 +void Mesh::set_attrib_location(int attr, int loc)
  24.331 +{
  24.332 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  24.333 +		return;
  24.334 +	}
  24.335 +	Mesh::global_sdr_loc[attr] = loc;
  24.336 +}
  24.337 +
  24.338 +/// static function
  24.339 +int Mesh::get_attrib_location(int attr)
  24.340 +{
  24.341 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  24.342 +		return -1;
  24.343 +	}
  24.344 +	return Mesh::global_sdr_loc[attr];
  24.345 +}
  24.346 +
  24.347 +/// static function
  24.348 +void Mesh::clear_attrib_locations()
  24.349 +{
  24.350 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.351 +		Mesh::global_sdr_loc[i] = -1;
  24.352 +	}
  24.353 +}
  24.354 +
  24.355 +/// static function
  24.356 +void Mesh::set_vis_vecsize(float sz)
  24.357 +{
  24.358 +	Mesh::vis_vecsize = sz;
  24.359 +}
  24.360 +
  24.361 +float Mesh::get_vis_vecsize()
  24.362 +{
  24.363 +	return Mesh::vis_vecsize;
  24.364 +}
  24.365 +
  24.366 +void Mesh::apply_xform(const Matrix4x4 &xform)
  24.367 +{
  24.368 +	Matrix4x4 dir_xform = xform;
  24.369 +	dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
  24.370 +	dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
  24.371 +	dir_xform[3][3] = 1.0f;
  24.372 +
  24.373 +	apply_xform(xform, dir_xform);
  24.374 +}
  24.375 +
  24.376 +void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
  24.377 +{
  24.378 +	for(unsigned int i=0; i<nverts; i++) {
  24.379 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
  24.380 +		set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
  24.381 +
  24.382 +		if(has_attrib(MESH_ATTR_NORMAL)) {
  24.383 +			Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
  24.384 +			set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
  24.385 +		}
  24.386 +		if(has_attrib(MESH_ATTR_TANGENT)) {
  24.387 +			Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
  24.388 +			set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
  24.389 +		}
  24.390 +	}
  24.391 +}
  24.392 +
  24.393 +int Mesh::add_bone(XFormNode *bone)
  24.394 +{
  24.395 +	int idx = bones.size();
  24.396 +	bones.push_back(bone);
  24.397 +	return idx;
  24.398 +}
  24.399 +
  24.400 +const XFormNode *Mesh::get_bone(int idx) const
  24.401 +{
  24.402 +	if(idx < 0 || idx >= (int)bones.size()) {
  24.403 +		return 0;
  24.404 +	}
  24.405 +	return bones[idx];
  24.406 +}
  24.407 +
  24.408 +int Mesh::get_bones_count() const
  24.409 +{
  24.410 +	return (int)bones.size();
  24.411 +}
  24.412 +
  24.413 +void Mesh::draw() const
  24.414 +{
  24.415 +	((Mesh*)this)->update_buffers();
  24.416 +
  24.417 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
  24.418 +		error_log("%s: invalid vertex buffer\n", __FUNCTION__);
  24.419 +		return;
  24.420 +	}
  24.421 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  24.422 +		error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
  24.423 +		return;
  24.424 +	}
  24.425 +
  24.426 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.427 +		int loc = global_sdr_loc[i];
  24.428 +		if(loc >= 0 && vattr[i].vbo_valid) {
  24.429 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  24.430 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  24.431 +			glEnableVertexAttribArray(loc);
  24.432 +		}
  24.433 +	}
  24.434 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  24.435 +
  24.436 +	if(ibo_valid) {
  24.437 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  24.438 +		glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
  24.439 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  24.440 +	} else {
  24.441 +		glDrawArrays(GL_TRIANGLES, 0, nverts);
  24.442 +	}
  24.443 +
  24.444 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.445 +		int loc = global_sdr_loc[i];
  24.446 +		if(loc >= 0 && vattr[i].vbo_valid) {
  24.447 +			glDisableVertexAttribArray(loc);
  24.448 +		}
  24.449 +	}
  24.450 +}
  24.451 +
  24.452 +void Mesh::draw_wire() const
  24.453 +{
  24.454 +	((Mesh*)this)->update_wire_ibo();
  24.455 +
  24.456 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
  24.457 +		error_log("%s: invalid vertex buffer\n", __FUNCTION__);
  24.458 +		return;
  24.459 +	}
  24.460 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  24.461 +		error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
  24.462 +		return;
  24.463 +	}
  24.464 +
  24.465 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.466 +		int loc = global_sdr_loc[i];
  24.467 +		if(loc >= 0 && vattr[i].vbo_valid) {
  24.468 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  24.469 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  24.470 +			glEnableVertexAttribArray(loc);
  24.471 +		}
  24.472 +	}
  24.473 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  24.474 +
  24.475 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
  24.476 +	glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
  24.477 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  24.478 +
  24.479 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.480 +		int loc = global_sdr_loc[i];
  24.481 +		if(loc >= 0 && vattr[i].vbo_valid) {
  24.482 +			glDisableVertexAttribArray(loc);
  24.483 +		}
  24.484 +	}
  24.485 +}
  24.486 +
  24.487 +void Mesh::draw_vertices() const
  24.488 +{
  24.489 +	((Mesh*)this)->update_buffers();
  24.490 +
  24.491 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
  24.492 +		error_log("%s: invalid vertex buffer\n", __FUNCTION__);
  24.493 +		return;
  24.494 +	}
  24.495 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  24.496 +		error_log("%s: shader attribute location for vertices unset\n", __FUNCTION__);
  24.497 +		return;
  24.498 +	}
  24.499 +
  24.500 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.501 +		int loc = global_sdr_loc[i];
  24.502 +		if(loc >= 0 && vattr[i].vbo_valid) {
  24.503 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  24.504 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  24.505 +			glEnableVertexAttribArray(loc);
  24.506 +		}
  24.507 +	}
  24.508 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  24.509 +
  24.510 +	glDrawArrays(GL_POINTS, 0, nverts);
  24.511 +
  24.512 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.513 +		int loc = global_sdr_loc[i];
  24.514 +		if(loc >= 0 && vattr[i].vbo_valid) {
  24.515 +			glDisableVertexAttribArray(loc);
  24.516 +		}
  24.517 +	}
  24.518 +}
  24.519 +
  24.520 +void Mesh::draw_normals() const
  24.521 +{
  24.522 +#ifdef USE_OLDGL
  24.523 +	int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  24.524 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  24.525 +	Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  24.526 +
  24.527 +	if(!varr || !norm || vert_loc < 0) {
  24.528 +		return;
  24.529 +	}
  24.530 +
  24.531 +	glBegin(GL_LINES);
  24.532 +	for(size_t i=0; i<nverts; i++) {
  24.533 +		glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  24.534 +		Vector3 end = varr[i] + norm[i] * vis_vecsize;
  24.535 +		glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  24.536 +	}
  24.537 +	glEnd();
  24.538 +
  24.539 +#endif	// USE_OLDGL
  24.540 +}
  24.541 +
  24.542 +void Mesh::draw_tangents() const
  24.543 +{
  24.544 +#ifdef USE_OLDGL
  24.545 +	int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  24.546 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  24.547 +	Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
  24.548 +
  24.549 +	if(!varr || !tang || vert_loc < 0) {
  24.550 +		return;
  24.551 +	}
  24.552 +
  24.553 +	glBegin(GL_LINES);
  24.554 +	for(size_t i=0; i<nverts; i++) {
  24.555 +		glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  24.556 +		Vector3 end = varr[i] + tang[i] * vis_vecsize;
  24.557 +		glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  24.558 +	}
  24.559 +	glEnd();
  24.560 +
  24.561 +#endif	// USE_OLDGL
  24.562 +}
  24.563 +
  24.564 +void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
  24.565 +{
  24.566 +	if(!aabb_valid) {
  24.567 +		((Mesh*)this)->calc_aabb();
  24.568 +	}
  24.569 +	*vmin = aabb.min;
  24.570 +	*vmax = aabb.max;
  24.571 +}
  24.572 +
  24.573 +const AABox &Mesh::get_aabbox() const
  24.574 +{
  24.575 +	if(!aabb_valid) {
  24.576 +		((Mesh*)this)->calc_aabb();
  24.577 +	}
  24.578 +	return aabb;
  24.579 +}
  24.580 +
  24.581 +float Mesh::get_bsphere(Vector3 *center, float *rad) const
  24.582 +{
  24.583 +	if(!bsph_valid) {
  24.584 +		((Mesh*)this)->calc_bsph();
  24.585 +	}
  24.586 +	*center = bsph.center;
  24.587 +	*rad = bsph.radius;
  24.588 +	return bsph.radius;
  24.589 +}
  24.590 +
  24.591 +const Sphere &Mesh::get_bsphere() const
  24.592 +{
  24.593 +	if(!bsph_valid) {
  24.594 +		((Mesh*)this)->calc_bsph();
  24.595 +	}
  24.596 +	return bsph;
  24.597 +}
  24.598 +
  24.599 +/// static function
  24.600 +void Mesh::set_intersect_mode(unsigned int mode)
  24.601 +{
  24.602 +	Mesh::intersect_mode = mode;
  24.603 +}
  24.604 +
  24.605 +/// static function
  24.606 +unsigned int Mesh::get_intersect_mode()
  24.607 +{
  24.608 +	return Mesh::intersect_mode;
  24.609 +}
  24.610 +
  24.611 +/// static function
  24.612 +void Mesh::set_vertex_select_distance(float dist)
  24.613 +{
  24.614 +	Mesh::vertex_sel_dist = dist;
  24.615 +}
  24.616 +
  24.617 +/// static function
  24.618 +float Mesh::get_vertex_select_distance()
  24.619 +{
  24.620 +	return Mesh::vertex_sel_dist;
  24.621 +}
  24.622 +
  24.623 +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
  24.624 +{
  24.625 +	assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
  24.626 +
  24.627 +	const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  24.628 +	const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  24.629 +	if(!varr) {
  24.630 +		return false;
  24.631 +	}
  24.632 +	const unsigned int *idxarr = get_index_data();
  24.633 +
  24.634 +	// first test with the bounding box
  24.635 +	AABox box;
  24.636 +	get_aabbox(&box.min, &box.max);
  24.637 +	if(!box.intersect(ray)) {
  24.638 +		return false;
  24.639 +	}
  24.640 +
  24.641 +	HitPoint nearest_hit;
  24.642 +	nearest_hit.dist = FLT_MAX;
  24.643 +	nearest_hit.obj = 0;
  24.644 +
  24.645 +	if(Mesh::intersect_mode & ISECT_VERTICES) {
  24.646 +		// we asked for "intersections" with the vertices of the mesh
  24.647 +		long nearest_vidx = -1;
  24.648 +		float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
  24.649 +
  24.650 +		for(unsigned int i=0; i<nverts; i++) {
  24.651 +
  24.652 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
  24.653 +				continue;
  24.654 +			}
  24.655 +
  24.656 +			// project the vertex onto the ray line
  24.657 +			float t = dot_product(varr[i] - ray.origin, ray.dir);
  24.658 +			Vector3 vproj = ray.origin + ray.dir * t;
  24.659 +
  24.660 +			float dist_sq = (vproj - varr[i]).length_sq();
  24.661 +			if(dist_sq < thres_sq) {
  24.662 +				if(!hit) {
  24.663 +					return true;
  24.664 +				}
  24.665 +				if(t < nearest_hit.dist) {
  24.666 +					nearest_hit.dist = t;
  24.667 +					nearest_vidx = i;
  24.668 +				}
  24.669 +			}
  24.670 +		}
  24.671 +
  24.672 +		if(nearest_vidx != -1) {
  24.673 +			hitvert = varr[nearest_vidx];
  24.674 +			nearest_hit.obj = &hitvert;
  24.675 +		}
  24.676 +
  24.677 +	} else {
  24.678 +		// regular intersection test with polygons
  24.679 +
  24.680 +		for(unsigned int i=0; i<nfaces; i++) {
  24.681 +			Triangle face(i, varr, idxarr);
  24.682 +
  24.683 +			// ignore back-facing polygons if the mode flags include ISECT_FRONT
  24.684 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
  24.685 +				continue;
  24.686 +			}
  24.687 +
  24.688 +			HitPoint fhit;
  24.689 +			if(face.intersect(ray, hit ? &fhit : 0)) {
  24.690 +				if(!hit) {
  24.691 +					return true;
  24.692 +				}
  24.693 +				if(fhit.dist < nearest_hit.dist) {
  24.694 +					nearest_hit = fhit;
  24.695 +					hitface = face;
  24.696 +				}
  24.697 +			}
  24.698 +		}
  24.699 +	}
  24.700 +
  24.701 +	if(nearest_hit.obj) {
  24.702 +		if(hit) {
  24.703 +			*hit = nearest_hit;
  24.704 +
  24.705 +			// if we are interested in the mesh and not the faces set obj to this
  24.706 +			if(Mesh::intersect_mode & ISECT_FACE) {
  24.707 +				hit->obj = &hitface;
  24.708 +			} else if(Mesh::intersect_mode & ISECT_VERTICES) {
  24.709 +				hit->obj = &hitvert;
  24.710 +			} else {
  24.711 +				hit->obj = this;
  24.712 +			}
  24.713 +		}
  24.714 +		return true;
  24.715 +	}
  24.716 +	return false;
  24.717 +}
  24.718 +
  24.719 +
  24.720 +// ------ private member functions ------
  24.721 +
  24.722 +void Mesh::calc_aabb()
  24.723 +{
  24.724 +	// the cast is to force calling the const version which doesn't invalidate
  24.725 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
  24.726 +		return;
  24.727 +	}
  24.728 +
  24.729 +	aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
  24.730 +	aabb.max = -aabb.min;
  24.731 +
  24.732 +	for(unsigned int i=0; i<nverts; i++) {
  24.733 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
  24.734 +		for(int j=0; j<3; j++) {
  24.735 +			if(v[j] < aabb.min[j]) {
  24.736 +				aabb.min[j] = v[j];
  24.737 +			}
  24.738 +			if(v[j] > aabb.max[j]) {
  24.739 +				aabb.max[j] = v[j];
  24.740 +			}
  24.741 +		}
  24.742 +	}
  24.743 +	aabb_valid = true;
  24.744 +}
  24.745 +
  24.746 +void Mesh::calc_bsph()
  24.747 +{
  24.748 +	// the cast is to force calling the const version which doesn't invalidate
  24.749 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
  24.750 +		return;
  24.751 +	}
  24.752 +
  24.753 +	Vector3 v;
  24.754 +	bsph.center = Vector3(0, 0, 0);
  24.755 +
  24.756 +	// first find the center
  24.757 +	for(unsigned int i=0; i<nverts; i++) {
  24.758 +		v = get_attrib(MESH_ATTR_VERTEX, i);
  24.759 +		bsph.center += v;
  24.760 +	}
  24.761 +	bsph.center /= (float)nverts;
  24.762 +
  24.763 +	bsph.radius = 0.0f;
  24.764 +	for(unsigned int i=0; i<nverts; i++) {
  24.765 +		v = get_attrib(MESH_ATTR_VERTEX, i);
  24.766 +		float dist_sq = (v - bsph.center).length_sq();
  24.767 +		if(dist_sq > bsph.radius) {
  24.768 +			bsph.radius = dist_sq;
  24.769 +		}
  24.770 +	}
  24.771 +	bsph.radius = sqrt(bsph.radius);
  24.772 +
  24.773 +	bsph_valid = true;
  24.774 +}
  24.775 +
  24.776 +void Mesh::update_buffers()
  24.777 +{
  24.778 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  24.779 +		if(has_attrib(i) && !vattr[i].vbo_valid) {
  24.780 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  24.781 +			glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
  24.782 +			vattr[i].vbo_valid = true;
  24.783 +		}
  24.784 +	}
  24.785 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  24.786 +
  24.787 +	if(idata_valid && !ibo_valid) {
  24.788 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  24.789 +		glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
  24.790 +		ibo_valid = true;
  24.791 +	}
  24.792 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  24.793 +}
  24.794 +
  24.795 +void Mesh::update_wire_ibo()
  24.796 +{
  24.797 +	update_buffers();
  24.798 +
  24.799 +	if(wire_ibo_valid) {
  24.800 +		return;
  24.801 +	}
  24.802 +
  24.803 +	if(!wire_ibo) {
  24.804 +		glGenBuffers(1, &wire_ibo);
  24.805 +	}
  24.806 +
  24.807 +	unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
  24.808 +	unsigned int *dest = wire_idxarr;
  24.809 +
  24.810 +	if(ibo_valid) {
  24.811 +		// we're dealing with an indexed mesh
  24.812 +		const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
  24.813 +
  24.814 +		for(unsigned int i=0; i<nfaces; i++) {
  24.815 +			*dest++ = idxarr[0];
  24.816 +			*dest++ = idxarr[1];
  24.817 +			*dest++ = idxarr[1];
  24.818 +			*dest++ = idxarr[2];
  24.819 +			*dest++ = idxarr[2];
  24.820 +			*dest++ = idxarr[0];
  24.821 +			idxarr += 3;
  24.822 +		}
  24.823 +	} else {
  24.824 +		// not an indexed mesh ...
  24.825 +		for(unsigned int i=0; i<nfaces; i++) {
  24.826 +			int vidx = i * 3;
  24.827 +			*dest++ = vidx;
  24.828 +			*dest++ = vidx + 1;
  24.829 +			*dest++ = vidx + 1;
  24.830 +			*dest++ = vidx + 2;
  24.831 +			*dest++ = vidx + 2;
  24.832 +			*dest++ = vidx;
  24.833 +		}
  24.834 +	}
  24.835 +
  24.836 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
  24.837 +	glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
  24.838 +	delete [] wire_idxarr;
  24.839 +	wire_ibo_valid = true;
  24.840 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  24.841 +}
  24.842 +
  24.843 +
  24.844 +// ------ class Triangle ------
  24.845 +Triangle::Triangle()
  24.846 +{
  24.847 +	normal_valid = false;
  24.848 +	id = -1;
  24.849 +}
  24.850 +
  24.851 +Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
  24.852 +{
  24.853 +	v[0] = v0;
  24.854 +	v[1] = v1;
  24.855 +	v[2] = v2;
  24.856 +	normal_valid = false;
  24.857 +	id = -1;
  24.858 +}
  24.859 +
  24.860 +Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
  24.861 +{
  24.862 +	if(idxarr) {
  24.863 +		v[0] = varr[idxarr[n * 3]];
  24.864 +		v[1] = varr[idxarr[n * 3 + 1]];
  24.865 +		v[2] = varr[idxarr[n * 3 + 2]];
  24.866 +	} else {
  24.867 +		v[0] = varr[n * 3];
  24.868 +		v[1] = varr[n * 3 + 1];
  24.869 +		v[2] = varr[n * 3 + 2];
  24.870 +	}
  24.871 +	normal_valid = false;
  24.872 +	id = n;
  24.873 +}
  24.874 +
  24.875 +void Triangle::calc_normal()
  24.876 +{
  24.877 +	normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
  24.878 +	normal_valid = true;
  24.879 +}
  24.880 +
  24.881 +const Vector3 &Triangle::get_normal() const
  24.882 +{
  24.883 +	if(!normal_valid) {
  24.884 +		((Triangle*)this)->calc_normal();
  24.885 +	}
  24.886 +	return normal;
  24.887 +}
  24.888 +
  24.889 +void Triangle::transform(const Matrix4x4 &xform)
  24.890 +{
  24.891 +	v[0].transform(xform);
  24.892 +	v[1].transform(xform);
  24.893 +	v[2].transform(xform);
  24.894 +	normal_valid = false;
  24.895 +}
  24.896 +
  24.897 +void Triangle::draw() const
  24.898 +{
  24.899 +	Vector3 n[3];
  24.900 +	n[0] = get_normal();
  24.901 +	n[1] = get_normal();
  24.902 +	n[2] = get_normal();
  24.903 +
  24.904 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
  24.905 +	int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
  24.906 +
  24.907 +	glEnableVertexAttribArray(vloc);
  24.908 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
  24.909 +	glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
  24.910 +
  24.911 +	glDrawArrays(GL_TRIANGLES, 0, 3);
  24.912 +
  24.913 +	glDisableVertexAttribArray(vloc);
  24.914 +	glDisableVertexAttribArray(nloc);
  24.915 +	CHECKGLERR;
  24.916 +}
  24.917 +
  24.918 +void Triangle::draw_wire() const
  24.919 +{
  24.920 +	static const int idxarr[] = {0, 1, 1, 2, 2, 0};
  24.921 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
  24.922 +
  24.923 +	glEnableVertexAttribArray(vloc);
  24.924 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
  24.925 +
  24.926 +	glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
  24.927 +
  24.928 +	glDisableVertexAttribArray(vloc);
  24.929 +	CHECKGLERR;
  24.930 +}
  24.931 +
  24.932 +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
  24.933 +{
  24.934 +	Vector3 norm = get_normal();
  24.935 +
  24.936 +	float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
  24.937 +	if(area_sq < 1e-5) {
  24.938 +		return Vector3(0, 0, 0);
  24.939 +	}
  24.940 +
  24.941 +	float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
  24.942 +	float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
  24.943 +	float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
  24.944 +
  24.945 +	return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
  24.946 +}
  24.947 +
  24.948 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
  24.949 +{
  24.950 +	Vector3 normal = get_normal();
  24.951 +
  24.952 +	float ndotdir = dot_product(ray.dir, normal);
  24.953 +	if(fabs(ndotdir) < 1e-4) {
  24.954 +		return false;
  24.955 +	}
  24.956 +
  24.957 +	Vector3 vertdir = v[0] - ray.origin;
  24.958 +	float t = dot_product(normal, vertdir) / ndotdir;
  24.959 +
  24.960 +	Vector3 pos = ray.origin + ray.dir * t;
  24.961 +	Vector3 bary = calc_barycentric(pos);
  24.962 +
  24.963 +	if(bary.x + bary.y + bary.z > 1.00001) {
  24.964 +		return false;
  24.965 +	}
  24.966 +
  24.967 +	if(hit) {
  24.968 +		hit->dist = t;
  24.969 +		hit->pos = ray.origin + ray.dir * t;
  24.970 +		hit->normal = normal;
  24.971 +		hit->obj = this;
  24.972 +	}
  24.973 +	return true;
  24.974 +}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/mesh.h	Thu Nov 14 05:27:09 2013 +0200
    25.3 @@ -0,0 +1,211 @@
    25.4 +#ifndef MESH_H_
    25.5 +#define MESH_H_
    25.6 +
    25.7 +#include <string>
    25.8 +#include <vector>
    25.9 +#include <vmath/vmath.h>
   25.10 +#include "geom.h"
   25.11 +
   25.12 +enum {
   25.13 +	MESH_ATTR_VERTEX,
   25.14 +	MESH_ATTR_NORMAL,
   25.15 +	MESH_ATTR_TANGENT,
   25.16 +	MESH_ATTR_TEXCOORD,
   25.17 +	MESH_ATTR_COLOR,
   25.18 +	MESH_ATTR_BONEWEIGHTS,
   25.19 +	MESH_ATTR_BONEIDX,
   25.20 +
   25.21 +	NUM_MESH_ATTR
   25.22 +};
   25.23 +
   25.24 +// intersection mode flags
   25.25 +enum {
   25.26 +	ISECT_DEFAULT	= 0,	// default (whole mesh, all intersections)
   25.27 +	ISECT_FRONT		= 1,	// front-faces only
   25.28 +	ISECT_FACE		= 2,	// return intersected face pointer instead of mesh
   25.29 +	ISECT_VERTICES	= 4		// return (?) TODO
   25.30 +};
   25.31 +
   25.32 +class XFormNode;
   25.33 +
   25.34 +
   25.35 +class Triangle {
   25.36 +public:
   25.37 +	Vector3 v[3];
   25.38 +	Vector3 normal;
   25.39 +	bool normal_valid;
   25.40 +	int id;
   25.41 +
   25.42 +	Triangle();
   25.43 +	Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2);
   25.44 +	Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0);
   25.45 +
   25.46 +	/// calculate normal (quite expensive)
   25.47 +	void calc_normal();
   25.48 +	const Vector3 &get_normal() const;
   25.49 +
   25.50 +	void transform(const Matrix4x4 &xform);
   25.51 +
   25.52 +	void draw() const;
   25.53 +	void draw_wire() const;
   25.54 +
   25.55 +	/// calculate barycentric coordinates of a point
   25.56 +	Vector3 calc_barycentric(const Vector3 &pos) const;
   25.57 +
   25.58 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   25.59 +};
   25.60 +
   25.61 +
   25.62 +class Mesh {
   25.63 +private:
   25.64 +	std::string name;
   25.65 +	unsigned int nverts, nfaces;
   25.66 +
   25.67 +	// current value for each attribute for the immedate mode
   25.68 +	// interface.
   25.69 +	Vector4 cur_val[NUM_MESH_ATTR];
   25.70 +
   25.71 +	unsigned int buffer_objects[NUM_MESH_ATTR + 1];
   25.72 +
   25.73 +	// vertex attribute data and buffer objects
   25.74 +	struct {
   25.75 +		int nelem;					// number of elements per attribute range: [1, 4]
   25.76 +		std::vector<float> data;
   25.77 +		unsigned int vbo;
   25.78 +		mutable bool vbo_valid;		// if this is false, the vbo needs updating from the data
   25.79 +		mutable bool data_valid;	// if this is false, the data needs to be pulled from the vbo
   25.80 +		//int sdr_loc;
   25.81 +	} vattr[NUM_MESH_ATTR];
   25.82 +
   25.83 +	static int global_sdr_loc[NUM_MESH_ATTR];
   25.84 +
   25.85 +	std::vector<XFormNode*> bones;	// bones affecting this mesh
   25.86 +
   25.87 +	// index data and buffer object
   25.88 +	std::vector<unsigned int> idata;
   25.89 +	unsigned int ibo;
   25.90 +	mutable bool ibo_valid;
   25.91 +	mutable bool idata_valid;
   25.92 +
   25.93 +	// index buffer object for wireframe rendering (constructed on demand)
   25.94 +	unsigned int wire_ibo;
   25.95 +	mutable bool wire_ibo_valid;
   25.96 +
   25.97 +	// axis-aligned bounding box
   25.98 +	mutable AABox aabb;
   25.99 +	mutable bool aabb_valid;
  25.100 +
  25.101 +	// bounding sphere
  25.102 +	mutable Sphere bsph;
  25.103 +	mutable bool bsph_valid;
  25.104 +
  25.105 +	// keeps the last intersected face
  25.106 +	mutable Triangle hitface;
  25.107 +	// keeps the last intersected vertex position
  25.108 +	mutable Vector3 hitvert;
  25.109 +
  25.110 +	void calc_aabb();
  25.111 +	void calc_bsph();
  25.112 +
  25.113 +	static unsigned int intersect_mode;
  25.114 +	static float vertex_sel_dist;
  25.115 +
  25.116 +	static float vis_vecsize;
  25.117 +
  25.118 +	/// update the VBOs after data has changed (invalid vbo/ibo)
  25.119 +	void update_buffers();
  25.120 +	/// construct/update the wireframe index buffer (called from draw_wire).
  25.121 +	void update_wire_ibo();
  25.122 +
  25.123 +
  25.124 +public:
  25.125 +	Mesh();
  25.126 +	~Mesh();
  25.127 +
  25.128 +	void set_name(const char *name);
  25.129 +	const char *get_name() const;
  25.130 +
  25.131 +	bool has_attrib(int attr) const;
  25.132 +
  25.133 +	// clears everything about this mesh, and returns to the newly constructed state
  25.134 +	void clear();
  25.135 +
  25.136 +	// access the vertex attribute data
  25.137 +	// if vdata == 0, space is just allocated
  25.138 +	float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo
  25.139 +	float *get_attrib_data(int attrib);	// invalidates vbo
  25.140 +	const float *get_attrib_data(int attrib) const;
  25.141 +
  25.142 +	// simple access to any particular attribute
  25.143 +	void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo
  25.144 +	Vector4 get_attrib(int attrib, int idx) const;
  25.145 +
  25.146 +	// ... same for index data
  25.147 +	unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo
  25.148 +	unsigned int *get_index_data();	// invalidates ibo
  25.149 +	const unsigned int *get_index_data() const;
  25.150 +
  25.151 +	void append(const Mesh &mesh);
  25.152 +
  25.153 +	// immediate-mode style mesh construction interface
  25.154 +	void vertex(float x, float y, float z);
  25.155 +	void normal(float nx, float ny, float nz);
  25.156 +	void tangent(float tx, float ty, float tz);
  25.157 +	void texcoord(float u, float v, float w);
  25.158 +	void boneweights(float w1, float w2, float w3, float w4);
  25.159 +	void boneidx(int idx1, int idx2, int idx3, int idx4);
  25.160 +
  25.161 +	/* apply a transformation to the vertices and its inverse-transpose
  25.162 +	 * to the normals and tangents.
  25.163 +	 */
  25.164 +	void apply_xform(const Matrix4x4 &xform);
  25.165 +	void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform);
  25.166 +
  25.167 +	// adds a bone and returns its index
  25.168 +	int add_bone(XFormNode *bone);
  25.169 +	const XFormNode *get_bone(int idx) const;
  25.170 +	int get_bones_count() const;
  25.171 +
  25.172 +	// access the shader attribute locations
  25.173 +	static void set_attrib_location(int attr, int loc);
  25.174 +	static int get_attrib_location(int attr);
  25.175 +	static void clear_attrib_locations();
  25.176 +
  25.177 +	static void set_vis_vecsize(float sz);
  25.178 +	static float get_vis_vecsize();
  25.179 +
  25.180 +	void draw() const;
  25.181 +	void draw_wire() const;
  25.182 +	void draw_vertices() const;
  25.183 +	void draw_normals() const;
  25.184 +	void draw_tangents() const;
  25.185 +
  25.186 +	/** get the bounding box in local space. The result will be cached, and subsequent
  25.187 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  25.188 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  25.189 +	 * @{ */
  25.190 +	void get_aabbox(Vector3 *vmin, Vector3 *vmax) const;
  25.191 +	const AABox &get_aabbox() const;
  25.192 +	/// @}
  25.193 +
  25.194 +	/** get the bounding sphere in local space. The result will be cached, and subsequent
  25.195 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  25.196 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  25.197 +	 * @{ */
  25.198 +	float get_bsphere(Vector3 *center, float *rad) const;
  25.199 +	const Sphere &get_bsphere() const;
  25.200 +
  25.201 +	static void set_intersect_mode(unsigned int mode);
  25.202 +	static unsigned int get_intersect_mode();
  25.203 +	static void set_vertex_select_distance(float dist);
  25.204 +	static float get_vertex_select_distance();
  25.205 +
  25.206 +	/** Find the intersection between the mesh and a ray.
  25.207 +	 * XXX Brute force at the moment, not intended to be used for anything other than picking in tools.
  25.208 +	 *     If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it!
  25.209 +	 */
  25.210 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
  25.211 +};
  25.212 +
  25.213 +
  25.214 +#endif	// MESH_H_
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/meshgen.cc	Thu Nov 14 05:27:09 2013 +0200
    26.3 @@ -0,0 +1,373 @@
    26.4 +#include "meshgen.h"
    26.5 +#include "mesh.h"
    26.6 +#include "logger.h"
    26.7 +
    26.8 +// -------- sphere --------
    26.9 +
   26.10 +#define SURAD(u)	((u) * 2.0 * M_PI)
   26.11 +#define SVRAD(v)	((v) * M_PI)
   26.12 +
   26.13 +static Vector3 sphvec(float theta, float phi)
   26.14 +{
   26.15 +	return Vector3(sin(theta) * sin(phi),
   26.16 +			cos(phi),
   26.17 +			cos(theta) * sin(phi));
   26.18 +}
   26.19 +
   26.20 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange)
   26.21 +{
   26.22 +	if(usub < 4) usub = 4;
   26.23 +	if(vsub < 2) vsub = 2;
   26.24 +
   26.25 +	int uverts = usub + 1;
   26.26 +	int vverts = vsub + 1;
   26.27 +
   26.28 +	int num_verts = uverts * vverts;
   26.29 +	int num_quads = usub * vsub;
   26.30 +	int num_tri = num_quads * 2;
   26.31 +
   26.32 +	mesh->clear();
   26.33 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
   26.34 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
   26.35 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
   26.36 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
   26.37 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
   26.38 +
   26.39 +	float du = urange / (float)(uverts - 1);
   26.40 +	float dv = vrange / (float)(vverts - 1);
   26.41 +
   26.42 +	float u = 0.0;
   26.43 +	for(int i=0; i<uverts; i++) {
   26.44 +		float theta = SURAD(u * urange);
   26.45 +
   26.46 +		float v = 0.0;
   26.47 +		for(int j=0; j<vverts; j++) {
   26.48 +			float phi = SVRAD(v * vrange);
   26.49 +
   26.50 +			Vector3 pos = sphvec(theta, phi);
   26.51 +
   26.52 +			*varr++ = pos * rad;
   26.53 +			*narr++ = pos;
   26.54 +			*tarr++ = (sphvec(theta + 0.1, M_PI / 2.0) - sphvec(theta - 0.1, M_PI / 2.0)).normalized();
   26.55 +			*uvarr++ = Vector2(u * urange, v * vrange);
   26.56 +
   26.57 +			if(i < usub && j < vsub) {
   26.58 +				int idx = i * vverts + j;
   26.59 +				*idxarr++ = idx;
   26.60 +				*idxarr++ = idx + 1;
   26.61 +				*idxarr++ = idx + vverts + 1;
   26.62 +
   26.63 +				*idxarr++ = idx;
   26.64 +				*idxarr++ = idx + vverts + 1;
   26.65 +				*idxarr++ = idx + vverts;
   26.66 +			}
   26.67 +
   26.68 +			v += dv;
   26.69 +		}
   26.70 +		u += du;
   26.71 +	}
   26.72 +}
   26.73 +
   26.74 +
   26.75 +// -------- cylinder --------
   26.76 +
   26.77 +static Vector3 cylvec(float theta, float height)
   26.78 +{
   26.79 +	return Vector3(sin(theta), height, cos(theta));
   26.80 +}
   26.81 +
   26.82 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
   26.83 +{
   26.84 +	if(usub < 4) usub = 4;
   26.85 +	if(vsub < 1) vsub = 1;
   26.86 +
   26.87 +	int uverts = usub + 1;
   26.88 +	int vverts = vsub + 1;
   26.89 +
   26.90 +	int num_body_verts = uverts * vverts;
   26.91 +	int num_body_quads = usub * vsub;
   26.92 +	int num_body_tri = num_body_quads * 2;
   26.93 +
   26.94 +	int capvverts = capsub ? capsub + 1 : 0;
   26.95 +	int num_cap_verts = uverts * capvverts;
   26.96 +	int num_cap_quads = usub * capsub;
   26.97 +	int num_cap_tri = num_cap_quads * 2;
   26.98 +
   26.99 +	int num_verts = num_body_verts + num_cap_verts * 2;
  26.100 +	int num_tri = num_body_tri + num_cap_tri * 2;
  26.101 +
  26.102 +	mesh->clear();
  26.103 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  26.104 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  26.105 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  26.106 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  26.107 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  26.108 +
  26.109 +	float du = urange / (float)(uverts - 1);
  26.110 +	float dv = vrange / (float)(vverts - 1);
  26.111 +
  26.112 +	float u = 0.0;
  26.113 +	for(int i=0; i<uverts; i++) {
  26.114 +		float theta = SURAD(u);
  26.115 +
  26.116 +		float v = 0.0;
  26.117 +		for(int j=0; j<vverts; j++) {
  26.118 +			float y = (v - 0.5) * height;
  26.119 +			Vector3 pos = cylvec(theta, y);
  26.120 +
  26.121 +			*varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad);
  26.122 +			*narr++ = Vector3(pos.x, 0.0, pos.z);
  26.123 +			*tarr++ = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  26.124 +			*uvarr++ = Vector2(u * urange, v * vrange);
  26.125 +
  26.126 +			if(i < usub && j < vsub) {
  26.127 +				int idx = i * vverts + j;
  26.128 +
  26.129 +				*idxarr++ = idx;
  26.130 +				*idxarr++ = idx + vverts + 1;
  26.131 +				*idxarr++ = idx + 1;
  26.132 +
  26.133 +				*idxarr++ = idx;
  26.134 +				*idxarr++ = idx + vverts;
  26.135 +				*idxarr++ = idx + vverts + 1;
  26.136 +			}
  26.137 +
  26.138 +			v += dv;
  26.139 +		}
  26.140 +		u += du;
  26.141 +	}
  26.142 +
  26.143 +
  26.144 +	// now the cap!
  26.145 +	if(!capsub) {
  26.146 +		return;
  26.147 +	}
  26.148 +
  26.149 +	dv = 1.0 / (float)(capvverts - 1);
  26.150 +
  26.151 +	u = 0.0;
  26.152 +	for(int i=0; i<uverts; i++) {
  26.153 +		float theta = SURAD(u);
  26.154 +
  26.155 +		float v = 0.0;
  26.156 +		for(int j=0; j<capvverts; j++) {
  26.157 +			float r = v * rad;
  26.158 +
  26.159 +			Vector3 pos = cylvec(theta, height / 2.0) * r;
  26.160 +			pos.y = height / 2.0;
  26.161 +			Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  26.162 +
  26.163 +			*varr++ = pos;
  26.164 +			*narr++ = Vector3(0, 1, 0);
  26.165 +			*tarr++ = tang;
  26.166 +			*uvarr++ = Vector2(u * urange, v);
  26.167 +
  26.168 +			pos.y = -height / 2.0;
  26.169 +			*varr++ = pos;
  26.170 +			*narr++ = Vector3(0, -1, 0);
  26.171 +			*tarr++ = -tang;
  26.172 +			*uvarr++ = Vector2(u * urange, v);
  26.173 +
  26.174 +			if(i < usub && j < capsub) {
  26.175 +				unsigned int idx = num_body_verts + (i * capvverts + j) * 2;
  26.176 +
  26.177 +				unsigned int vidx[4] = {
  26.178 +					idx,
  26.179 +					idx + capvverts * 2,
  26.180 +					idx + (capvverts + 1) * 2,
  26.181 +					idx + 2
  26.182 +				};
  26.183 +
  26.184 +				*idxarr++ = vidx[0];
  26.185 +				*idxarr++ = vidx[2];
  26.186 +				*idxarr++ = vidx[1];
  26.187 +				*idxarr++ = vidx[0];
  26.188 +				*idxarr++ = vidx[3];
  26.189 +				*idxarr++ = vidx[2];
  26.190 +
  26.191 +				*idxarr++ = vidx[0] + 1;
  26.192 +				*idxarr++ = vidx[1] + 1;
  26.193 +				*idxarr++ = vidx[2] + 1;
  26.194 +				*idxarr++ = vidx[0] + 1;
  26.195 +				*idxarr++ = vidx[2] + 1;
  26.196 +				*idxarr++ = vidx[3] + 1;
  26.197 +			}
  26.198 +
  26.199 +			v += dv;
  26.200 +		}
  26.201 +		u += du;
  26.202 +	}
  26.203 +}
  26.204 +
  26.205 +// -------- cone --------
  26.206 +
  26.207 +static Vector3 conevec(float theta, float y, float height)
  26.208 +{
  26.209 +	float scale = 1.0 - y / height;
  26.210 +	return Vector3(sin(theta) * scale, y, cos(theta) * scale);
  26.211 +}
  26.212 +
  26.213 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
  26.214 +{
  26.215 +	if(usub < 4) usub = 4;
  26.216 +	if(vsub < 1) vsub = 1;
  26.217 +
  26.218 +	int uverts = usub + 1;
  26.219 +	int vverts = vsub + 1;
  26.220 +
  26.221 +	int num_body_verts = uverts * vverts;
  26.222 +	int num_body_quads = usub * vsub;
  26.223 +	int num_body_tri = num_body_quads * 2;
  26.224 +
  26.225 +	int capvverts = capsub ? capsub + 1 : 0;
  26.226 +	int num_cap_verts = uverts * capvverts;
  26.227 +	int num_cap_quads = usub * capsub;
  26.228 +	int num_cap_tri = num_cap_quads * 2;
  26.229 +
  26.230 +	int num_verts = num_body_verts + num_cap_verts;
  26.231 +	int num_tri = num_body_tri + num_cap_tri;
  26.232 +
  26.233 +	mesh->clear();
  26.234 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  26.235 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  26.236 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  26.237 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  26.238 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  26.239 +
  26.240 +	float du = urange / (float)(uverts - 1);
  26.241 +	float dv = vrange / (float)(vverts - 1);
  26.242 +
  26.243 +	float u = 0.0;
  26.244 +	for(int i=0; i<uverts; i++) {
  26.245 +		float theta = SURAD(u);
  26.246 +
  26.247 +		float v = 0.0;
  26.248 +		for(int j=0; j<vverts; j++) {
  26.249 +			float y = v * height;
  26.250 +			Vector3 pos = conevec(theta, y, height);
  26.251 +
  26.252 +			Vector3 tang = (conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height)).normalized();
  26.253 +			Vector3 bitang = (conevec(theta, y + 0.1, height) - pos).normalized();
  26.254 +
  26.255 +			*varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad);
  26.256 +			*narr++ = cross_product(tang, bitang);
  26.257 +			*tarr++ = tang;
  26.258 +			*uvarr++ = Vector2(u * urange, v * vrange);
  26.259 +
  26.260 +			if(i < usub && j < vsub) {
  26.261 +				int idx = i * vverts + j;
  26.262 +
  26.263 +				*idxarr++ = idx;
  26.264 +				*idxarr++ = idx + vverts + 1;
  26.265 +				*idxarr++ = idx + 1;
  26.266 +
  26.267 +				*idxarr++ = idx;
  26.268 +				*idxarr++ = idx + vverts;
  26.269 +				*idxarr++ = idx + vverts + 1;
  26.270 +			}
  26.271 +
  26.272 +			v += dv;
  26.273 +		}
  26.274 +		u += du;
  26.275 +	}
  26.276 +
  26.277 +
  26.278 +	// now the bottom cap!
  26.279 +	if(!capsub) {
  26.280 +		return;
  26.281 +	}
  26.282 +
  26.283 +	dv = 1.0 / (float)(capvverts - 1);
  26.284 +
  26.285 +	u = 0.0;
  26.286 +	for(int i=0; i<uverts; i++) {
  26.287 +		float theta = SURAD(u);
  26.288 +
  26.289 +		float v = 0.0;
  26.290 +		for(int j=0; j<capvverts; j++) {
  26.291 +			float r = v * rad;
  26.292 +
  26.293 +			Vector3 pos = conevec(theta, 0.0, height) * r;
  26.294 +			Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  26.295 +
  26.296 +			*varr++ = pos;
  26.297 +			*narr++ = Vector3(0, -1, 0);
  26.298 +			*tarr++ = tang;
  26.299 +			*uvarr++ = Vector2(u * urange, v);
  26.300 +
  26.301 +			if(i < usub && j < capsub) {
  26.302 +				unsigned int idx = num_body_verts + i * capvverts + j;
  26.303 +
  26.304 +				unsigned int vidx[4] = {
  26.305 +					idx,
  26.306 +					idx + capvverts,
  26.307 +					idx + (capvverts + 1),
  26.308 +					idx + 1
  26.309 +				};
  26.310 +
  26.311 +				*idxarr++ = vidx[0];
  26.312 +				*idxarr++ = vidx[1];
  26.313 +				*idxarr++ = vidx[2];
  26.314 +				*idxarr++ = vidx[0];
  26.315 +				*idxarr++ = vidx[2];
  26.316 +				*idxarr++ = vidx[3];
  26.317 +			}
  26.318 +
  26.319 +			v += dv;
  26.320 +		}
  26.321 +		u += du;
  26.322 +	}
  26.323 +}
  26.324 +
  26.325 +
  26.326 +// -------- plane --------
  26.327 +
  26.328 +void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub)
  26.329 +{
  26.330 +	if(usub < 1) usub = 1;
  26.331 +	if(vsub < 1) vsub = 1;
  26.332 +
  26.333 +	mesh->clear();
  26.334 +
  26.335 +	int uverts = usub + 1;
  26.336 +	int vverts = vsub + 1;
  26.337 +	int num_verts = uverts * vverts;
  26.338 +
  26.339 +	int num_quads = usub * vsub;
  26.340 +	int num_tri = num_quads * 2;
  26.341 +
  26.342 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  26.343 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  26.344 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  26.345 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  26.346 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  26.347 +
  26.348 +	float du = 1.0 / (float)usub;
  26.349 +	float dv = 1.0 / (float)vsub;
  26.350 +
  26.351 +	float u = 0.0;
  26.352 +	for(int i=0; i<uverts; i++) {
  26.353 +		float v = 0.0;
  26.354 +		for(int j=0; j<vverts; j++) {
  26.355 +			*varr++ = Vector3((u - 0.5) * width, (v - 0.5) * height, 0.0);
  26.356 +			*narr++ = Vector3(0, 0, 1);
  26.357 +			*tarr++ = Vector3(1, 0, 0);
  26.358 +			*uvarr++ = Vector2(u, v);
  26.359 +
  26.360 +			if(i < usub && j < vsub) {
  26.361 +				int idx = i * vverts + j;
  26.362 +
  26.363 +				*idxarr++ = idx;
  26.364 +				*idxarr++ = idx + vverts + 1;
  26.365 +				*idxarr++ = idx + 1;
  26.366 +
  26.367 +				*idxarr++ = idx;
  26.368 +				*idxarr++ = idx + vverts;
  26.369 +				*idxarr++ = idx + vverts + 1;
  26.370 +			}
  26.371 +
  26.372 +			v += dv;
  26.373 +		}
  26.374 +		u += du;
  26.375 +	}
  26.376 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/src/meshgen.h	Thu Nov 14 05:27:09 2013 +0200
    27.3 @@ -0,0 +1,11 @@
    27.4 +#ifndef MESHGEN_H_
    27.5 +#define MESHGEN_H_
    27.6 +
    27.7 +class Mesh;
    27.8 +
    27.9 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange = 1.0, float vrange = 1.0);
   27.10 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0);
   27.11 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0);
   27.12 +void gen_plane(Mesh *mesh, float width, float height, int usub = 1, int vsub = 1);
   27.13 +
   27.14 +#endif	// MESHGEN_H_
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/object.cc	Thu Nov 14 05:27:09 2013 +0200
    28.3 @@ -0,0 +1,284 @@
    28.4 +#include <float.h>
    28.5 +#include "object.h"
    28.6 +#include "opengl.h"
    28.7 +#include "unistate.h"
    28.8 +#include "logger.h"
    28.9 +
   28.10 +static void destroy_all_rec(XFormNode *node);
   28.11 +static void get_all_meshes_rec(XFormNode *node, std::list<Mesh*> *reslist);
   28.12 +
   28.13 +DrawMode Object::draw_mode = DRAW_DEFAULT;
   28.14 +
   28.15 +Object::Object()
   28.16 +{
   28.17 +	mesh = 0;
   28.18 +}
   28.19 +
   28.20 +void Object::destroy_all()
   28.21 +{
   28.22 +	destroy_all_rec(this);
   28.23 +}
   28.24 +
   28.25 +static void destroy_all_rec(XFormNode *node)
   28.26 +{
   28.27 +	if(!node) {
   28.28 +		return;
   28.29 +	}
   28.30 +
   28.31 +	for(int i=0; i<node->get_children_count(); i++) {
   28.32 +		destroy_all_rec(node->get_child(i));
   28.33 +	}
   28.34 +	delete node;
   28.35 +}
   28.36 +
   28.37 +void Object::set_mesh(Mesh *m)
   28.38 +{
   28.39 +	mesh = m;
   28.40 +}
   28.41 +
   28.42 +Mesh *Object::get_mesh()
   28.43 +{
   28.44 +	return mesh;
   28.45 +}
   28.46 +
   28.47 +const Mesh *Object::get_mesh() const
   28.48 +{
   28.49 +	return mesh;
   28.50 +}
   28.51 +
   28.52 +std::list<Mesh*> Object::get_all_meshes()
   28.53 +{
   28.54 +	std::list<Mesh*> meshes;
   28.55 +	get_all_meshes_rec(this, &meshes);
   28.56 +	return meshes;
   28.57 +}
   28.58 +
   28.59 +std::list<const Mesh*> Object::get_all_meshes() const
   28.60 +{
   28.61 +	std::list<const Mesh*> meshes;
   28.62 +	get_all_meshes_rec((Object*)this, (std::list<Mesh*>*)&meshes);
   28.63 +	return meshes;
   28.64 +}
   28.65 +
   28.66 +static void get_all_meshes_rec(XFormNode *node, std::list<Mesh*> *reslist)
   28.67 +{
   28.68 +	if(!node) {
   28.69 +		return;
   28.70 +	}
   28.71 +
   28.72 +	Object *obj = dynamic_cast<Object*>(node);
   28.73 +	if(obj) {
   28.74 +		Mesh *mesh = obj->get_mesh();
   28.75 +		if(mesh) {
   28.76 +			reslist->push_back(mesh);
   28.77 +		}
   28.78 +	}
   28.79 +
   28.80 +	for(int i=0; i<node->get_children_count(); i++) {
   28.81 +		get_all_meshes_rec(node->get_child(i), reslist);
   28.82 +	}
   28.83 +}
   28.84 +
   28.85 +AABox Object::get_aabbox() const
   28.86 +{
   28.87 +	AABox box;
   28.88 +
   28.89 +	if(mesh) {
   28.90 +		box = mesh->get_aabbox();
   28.91 +	} else {
   28.92 +		box.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
   28.93 +		box.max = -box.min;
   28.94 +	}
   28.95 +
   28.96 +	int num_children = get_children_count();
   28.97 +	for(int i=0; i<num_children; i++) {
   28.98 +		const Object *obj = dynamic_cast<const Object*>(get_child(i));
   28.99 +		if(obj) {
  28.100 +			AABox child_box = obj->get_aabbox();
  28.101 +			box.set_union(&box, &child_box);
  28.102 +		}
  28.103 +	}
  28.104 +	return box;
  28.105 +}
  28.106 +
  28.107 +Sphere Object::get_bsphere() const
  28.108 +{
  28.109 +	Sphere sph;
  28.110 +	bool valid = false;
  28.111 +
  28.112 +	if(mesh) {
  28.113 +		sph = mesh->get_bsphere();
  28.114 +		valid = true;
  28.115 +	} else {
  28.116 +		sph.radius = 0.0;
  28.117 +	}
  28.118 +
  28.119 +	int num_children = get_children_count();
  28.120 +	for(int i=0; i<num_children; i++) {
  28.121 +		const Object *obj = dynamic_cast<const Object*>(get_child(i));
  28.122 +		if(obj) {
  28.123 +			Sphere child_sph = obj->get_bsphere();
  28.124 +			if(valid) {
  28.125 +				sph.set_union(&sph, &child_sph);
  28.126 +			} else {
  28.127 +				sph = child_sph;
  28.128 +				valid = true;
  28.129 +			}
  28.130 +		}
  28.131 +	}
  28.132 +
  28.133 +	return sph;
  28.134 +}
  28.135 +
  28.136 +/*static const char *attr_name[] = {
  28.137 +	"attr_vertex",
  28.138 +	"attr_normal",
  28.139 +	"attr_tangent",
  28.140 +	"attr_texcoord",
  28.141 +	"attr_boneweights",
  28.142 +	"attr_boneidx"
  28.143 +};*/
  28.144 +
  28.145 +void Object::draw(long msec) const
  28.146 +{
  28.147 +	Matrix4x4 xform;
  28.148 +	get_xform(msec, &xform);
  28.149 +
  28.150 +	set_world_matrix(xform);
  28.151 +
  28.152 +	if(mesh) {
  28.153 +		/*unsigned int prog = sdrprog;
  28.154 +
  28.155 +		if(mesh->get_bones_count() > 0) {
  28.156 +			prog = sdrprog_skin;
  28.157 +		}
  28.158 +
  28.159 +		glUseProgram(prog);
  28.160 +		// get all the attribute locations
  28.161 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  28.162 +			int loc = glGetAttribLocation(prog, attr_name[i]);
  28.163 +			if(loc != -1) {
  28.164 +				Mesh::set_attrib_location(i, loc);
  28.165 +			}
  28.166 +		}
  28.167 +
  28.168 +		setup_bones(msec);
  28.169 +
  28.170 +		glUseProgram(prog);*/
  28.171 +
  28.172 +		material.setup();
  28.173 +		setup_unistate();	// set all state uniforms
  28.174 +
  28.175 +		switch(Object::draw_mode) {
  28.176 +		case DRAW_WIREFRAME:
  28.177 +			mesh->draw_wire();
  28.178 +			break;
  28.179 +
  28.180 +		case DRAW_VERTICES:
  28.181 +			mesh->draw_vertices();
  28.182 +			break;
  28.183 +
  28.184 +		case DRAW_DEFAULT:
  28.185 +		default:
  28.186 +			mesh->draw();
  28.187 +		}
  28.188 +	}
  28.189 +
  28.190 +	int num_children = get_children_count();
  28.191 +	for(int i=0; i<num_children; i++) {
  28.192 +		const Object *obj = dynamic_cast<const Object*>(get_child(i));
  28.193 +		if(obj) {
  28.194 +			obj->draw(msec);
  28.195 +		}
  28.196 +	}
  28.197 +}
  28.198 +
  28.199 +
  28.200 +bool Object::intersect(const Ray &inray, HitPoint *hit) const
  28.201 +{
  28.202 +	Ray ray = inray;
  28.203 +	Matrix4x4 xform, inv_xform;
  28.204 +	get_xform(ray.time, &xform/*, &inv_xform*/);
  28.205 +	ray.transform(xform.inverse());	// TODO find out what's wrong with get_xform's inv_xform and use that
  28.206 +
  28.207 +	HitPoint nearest_hit;
  28.208 +	nearest_hit.dist = FLT_MAX;
  28.209 +	nearest_hit.obj = 0;
  28.210 +
  28.211 +	if(mesh) {
  28.212 +		if(mesh->intersect(ray, hit ? &nearest_hit : 0)) {
  28.213 +			if(!hit) {
  28.214 +				return true;
  28.215 +			}
  28.216 +
  28.217 +			if(Mesh::get_intersect_mode() & ISECT_FACE) {
  28.218 +				Triangle *face = (Triangle*)nearest_hit.obj;
  28.219 +				face->transform(xform);
  28.220 +			} else if(Mesh::get_intersect_mode() & ISECT_VERTICES) {
  28.221 +				Vector3 *v = (Vector3*)nearest_hit.obj;
  28.222 +				v->transform(xform);
  28.223 +			} else {
  28.224 +				nearest_hit.obj = this;
  28.225 +			}
  28.226 +		}
  28.227 +	}
  28.228 +
  28.229 +	int num_children = get_children_count();
  28.230 +	for(int i=0; i<num_children; i++) {
  28.231 +		const Object *obj = dynamic_cast<const Object*>(get_child(i));
  28.232 +
  28.233 +		HitPoint chit;
  28.234 +		if(obj && obj->intersect(inray, hit ? &chit : 0)) {
  28.235 +			if(!hit) {
  28.236 +				return true;
  28.237 +			}
  28.238 +
  28.239 +			if(chit.dist < nearest_hit.dist) {
  28.240 +				nearest_hit = chit;
  28.241 +			}
  28.242 +		}
  28.243 +	}
  28.244 +
  28.245 +	if(nearest_hit.obj) {
  28.246 +		if(hit) {
  28.247 +			*hit = nearest_hit;
  28.248 +		}
  28.249 +		return true;
  28.250 +	}
  28.251 +	return false;
  28.252 +}
  28.253 +
  28.254 +
  28.255 +bool Object::setup_bones(long msec) const
  28.256 +{
  28.257 +	int num_bones;
  28.258 +	if(!mesh || !(num_bones = mesh->get_bones_count())) {
  28.259 +		return false;
  28.260 +	}
  28.261 +
  28.262 +	/*char uniname[32];
  28.263 +
  28.264 +	for(int i=0; i<num_bones; i++) {
  28.265 +		const XFormNode *bone = mesh->get_bone(i);
  28.266 +
  28.267 +		Matrix4x4 xform;
  28.268 +		bone->get_xform(msec, &xform);
  28.269 +
  28.270 +		xform = xform * bone->get_bone_matrix();
  28.271 +
  28.272 +		sprintf(uniname, "bone_xform[%d]", i);
  28.273 +		int loc = glGetUniformLocation(sdrprog_skin, uniname);
  28.274 +		if(loc == -1) {
  28.275 +			return false;
  28.276 +		}
  28.277 +		glUniformMatrix4fv(loc, 1, GL_TRUE, xform[0]);
  28.278 +	}*/
  28.279 +	return true;
  28.280 +}
  28.281 +
  28.282 +DrawMode Object::set_draw_mode(DrawMode mode)
  28.283 +{
  28.284 +	DrawMode prev = Object::draw_mode;
  28.285 +	Object::draw_mode = mode;
  28.286 +	return prev;
  28.287 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/object.h	Thu Nov 14 05:27:09 2013 +0200
    29.3 @@ -0,0 +1,51 @@
    29.4 +#ifndef OBJECT_H_
    29.5 +#define OBJECT_H_
    29.6 +
    29.7 +#include <list>
    29.8 +#include "xform_node.h"
    29.9 +#include "mesh.h"
   29.10 +#include "material.h"
   29.11 +
   29.12 +enum DrawMode {
   29.13 +	DRAW_DEFAULT,
   29.14 +	DRAW_WIREFRAME,
   29.15 +	DRAW_VERTICES
   29.16 +};
   29.17 +
   29.18 +
   29.19 +class Object : public XFormNode {
   29.20 +private:
   29.21 +	Mesh *mesh;	///< no ownership, just keeping the pointer around
   29.22 +	static DrawMode draw_mode;
   29.23 +
   29.24 +	bool setup_bones(long msec) const;
   29.25 +
   29.26 +public:
   29.27 +	Material material;
   29.28 +
   29.29 +	Object();
   29.30 +
   29.31 +	/// destroy this object and all the hierarchy of objects hanging below it
   29.32 +	void destroy_all();
   29.33 +
   29.34 +	void set_mesh(Mesh *m);
   29.35 +	Mesh *get_mesh();
   29.36 +	const Mesh *get_mesh() const;
   29.37 +
   29.38 +	/// get all the meshes of the subtree rooted in this object @{
   29.39 +	std::list<Mesh*> get_all_meshes();
   29.40 +	std::list<const Mesh*> get_all_meshes() const;
   29.41 +	/// @}
   29.42 +
   29.43 +	AABox get_aabbox() const;
   29.44 +	Sphere get_bsphere() const;
   29.45 +
   29.46 +	void draw(long msec = 0) const;
   29.47 +
   29.48 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   29.49 +
   29.50 +	/// this is mostly for tools, to allow drawing only the wireframe or vertices
   29.51 +	static DrawMode set_draw_mode(DrawMode mode);
   29.52 +};
   29.53 +
   29.54 +#endif	// OBJECT_H_
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/opengl.cc	Thu Nov 14 05:27:09 2013 +0200
    30.3 @@ -0,0 +1,29 @@
    30.4 +#include "opengl.h"
    30.5 +
    30.6 +void init_opengl()
    30.7 +{
    30.8 +#ifdef __GLEW_H__
    30.9 +	glewInit();
   30.10 +#endif
   30.11 +}
   30.12 +
   30.13 +const char *strglerr(int err)
   30.14 +{
   30.15 +	static const char *errnames[] = {
   30.16 +		"GL_INVALID_ENUM",
   30.17 +		"GL_INVALID_VALUE",
   30.18 +		"GL_INVALID_OPERATION",
   30.19 +		"GL_STACK_OVERFLOW",
   30.20 +		"GL_STACK_UNDERFLOW",
   30.21 +		"GL_OUT_OF_MEMORY",
   30.22 +		"GL_INVALID_FRAMEBUFFER_OPERATION"
   30.23 +	};
   30.24 +
   30.25 +	if(!err) {
   30.26 +		return "GL_NO_ERROR";
   30.27 +	}
   30.28 +	if(err < GL_INVALID_ENUM || err > GL_OUT_OF_MEMORY) {
   30.29 +		return "<invalid gl error>";
   30.30 +	}
   30.31 +	return errnames[err - GL_INVALID_ENUM];
   30.32 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/opengl.h	Thu Nov 14 05:27:09 2013 +0200
    31.3 @@ -0,0 +1,71 @@
    31.4 +#ifndef OPENGL_H_
    31.5 +#define OPENGL_H_
    31.6 +
    31.7 +#include <stdlib.h>
    31.8 +
    31.9 +#ifdef __APPLE__
   31.10 +#include "TargetConditionals.h"
   31.11 +
   31.12 +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
   31.13 +/* iOS */
   31.14 +#include <OpenGLES/ES2/gl.h>
   31.15 +#include <OpenGLES/ES2/glext.h>
   31.16 +
   31.17 +#define GL_CLAMP			GL_CLAMP_TO_EDGE
   31.18 +#define GL_DEPTH24_STENCIL8	GL_DEPTH24_STENCIL8_OES
   31.19 +
   31.20 +#undef USE_OLDGL
   31.21 +
   31.22 +#define GL_WRITE_ONLY	GL_WRITE_ONLY_OES
   31.23 +#define glMapBuffer		glMapBufferOES
   31.24 +#define glUnmapBuffer	glUnmapBufferOES
   31.25 +
   31.26 +#else
   31.27 +/* MacOS X */
   31.28 +#include <GL/glew.h>
   31.29 +#include <GLUT/glut.h>
   31.30 +
   31.31 +#define USE_OLDGL
   31.32 +#endif
   31.33 +
   31.34 +#else
   31.35 +/* UNIX or Windows */
   31.36 +#include <GL/glew.h>
   31.37 +#include <GL/glut.h>
   31.38 +
   31.39 +#define USE_OLDGL
   31.40 +#endif
   31.41 +
   31.42 +#ifndef GL_RGB16F
   31.43 +#define GL_RGB16F	0x881b
   31.44 +#endif
   31.45 +#ifndef GL_RGBA16F
   31.46 +#define GL_RGBA16F	0x881a
   31.47 +#endif
   31.48 +#ifndef GL_RGB32F
   31.49 +#define GL_RGB32F	0x8815
   31.50 +#endif
   31.51 +#ifndef GL_RGBA32F
   31.52 +#define GL_RGBA32F	0x8814
   31.53 +#endif
   31.54 +#ifndef GL_LUMINANCE16F
   31.55 +#define GL_LUMINANCE16F	0x881e
   31.56 +#endif
   31.57 +#ifndef GL_LUMINANCE32F
   31.58 +#define GL_LUMINANCE32F	0x8818
   31.59 +#endif
   31.60 +
   31.61 +#define CHECKGLERR	\
   31.62 +	do { \
   31.63 +		int err = glGetError(); \
   31.64 +		if(err) { \
   31.65 +			fprintf(stderr, "%s:%d: OpenGL error 0x%x: %s\n", __FILE__, __LINE__, err, strglerr(err)); \
   31.66 +			abort(); \
   31.67 +		} \
   31.68 +	} while(0)
   31.69 +
   31.70 +void init_opengl();
   31.71 +
   31.72 +const char *strglerr(int err);
   31.73 +
   31.74 +#endif	// OPENGL_H_
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/src/psyspp.cc	Thu Nov 14 05:27:09 2013 +0200
    32.3 @@ -0,0 +1,459 @@
    32.4 +#include <limits.h>
    32.5 +#include "psyspp.h"
    32.6 +#include "sdrman.h"
    32.7 +#include "logger.h"
    32.8 +#include "mesh.h"	// just for the attrib enums
    32.9 +#include "unistate.h"
   32.10 +#include "datapath.h"
   32.11 +#include "texman.h"
   32.12 +#include "texgen.h"
   32.13 +
   32.14 +static void pdraw_start(const psys_emitter *em, void *cls);
   32.15 +static void pdraw(const psys_emitter *em, const psys_particle *part, void *cls);
   32.16 +static void pdraw_end(const psys_emitter *em, void *cls);
   32.17 +
   32.18 +static unsigned int psys_load_texture(const char *fname, void *cls);
   32.19 +
   32.20 +ParticleSystemAttributes::ParticleSystemAttributes()
   32.21 +{
   32.22 +	tex = 0;
   32.23 +	own_psattr = true;
   32.24 +	psattr = new psys_attributes;
   32.25 +	psys_init_attr(psattr);
   32.26 +}
   32.27 +
   32.28 +ParticleSystemAttributes::ParticleSystemAttributes(psys_attributes *psattr)
   32.29 +{
   32.30 +	tex = 0;
   32.31 +	own_psattr = false;
   32.32 +	this->psattr = psattr;
   32.33 +}
   32.34 +
   32.35 +ParticleSystemAttributes::~ParticleSystemAttributes()
   32.36 +{
   32.37 +	if(own_psattr) {
   32.38 +		psys_destroy_attr(psattr);
   32.39 +		delete psattr;
   32.40 +	}
   32.41 +}
   32.42 +
   32.43 +ParticleSystemAttributes::ParticleSystemAttributes(const ParticleSystemAttributes &rhs)
   32.44 +{
   32.45 +	own_psattr = true;
   32.46 +	tex = rhs.tex;
   32.47 +	psattr = new psys_attributes;
   32.48 +	psys_init_attr(psattr);
   32.49 +
   32.50 +	psys_copy_attr(psattr, rhs.psattr);
   32.51 +}
   32.52 +
   32.53 +ParticleSystemAttributes &ParticleSystemAttributes::operator =(const ParticleSystemAttributes &rhs)
   32.54 +{
   32.55 +	if(&rhs != this) {
   32.56 +		tex = rhs.tex;
   32.57 +		psys_copy_attr(psattr, rhs.psattr);
   32.58 +	}
   32.59 +	return *this;
   32.60 +}
   32.61 +
   32.62 +bool ParticleSystemAttributes::load(const char *fname)
   32.63 +{
   32.64 +	psys_texture_loader(psys_load_texture, 0, this);
   32.65 +	return psys_load_attr(psattr, datafile_path(fname).c_str()) != -1;
   32.66 +}
   32.67 +
   32.68 +bool ParticleSystemAttributes::load(FILE *fp)
   32.69 +{
   32.70 +	psys_texture_loader(psys_load_texture, 0, this);
   32.71 +	return psys_load_attr_stream(psattr, fp) != -1;
   32.72 +}
   32.73 +
   32.74 +bool ParticleSystemAttributes::save(const char *fname) const
   32.75 +{
   32.76 +	return psys_save_attr(psattr, fname) != -1;
   32.77 +}
   32.78 +
   32.79 +bool ParticleSystemAttributes::save(FILE *fp) const
   32.80 +{
   32.81 +	return psys_save_attr_stream(psattr, fp) != -1;
   32.82 +}
   32.83 +
   32.84 +void ParticleSystemAttributes::set_part_color(const Vector3 &color, float t)
   32.85 +{
   32.86 +	psys_set_value3(&psattr->part_attr.color, (anm_time_t)(t * 1000.0), v3_cons(color.x, color.y, color.z));
   32.87 +}
   32.88 +
   32.89 +void ParticleSystemAttributes::set_part_alpha(float alpha, float t)
   32.90 +{
   32.91 +	psys_set_value(&psattr->part_attr.alpha, (anm_time_t)(t * 1000.0), alpha);
   32.92 +}
   32.93 +
   32.94 +void ParticleSystemAttributes::set_part_scale(float size, float t)
   32.95 +{
   32.96 +	psys_set_value(&psattr->part_attr.size, (anm_time_t)(t * 1000.0), size);
   32.97 +}
   32.98 +
   32.99 +
  32.100 +// emmiter attributes
  32.101 +void ParticleSystemAttributes::set_texture(Texture *tex)
  32.102 +{
  32.103 +	this->tex = tex;
  32.104 +	psattr->tex = tex->get_id();
  32.105 +}
  32.106 +
  32.107 +Texture *ParticleSystemAttributes::get_texture() const
  32.108 +{
  32.109 +	return tex;
  32.110 +}
  32.111 +
  32.112 +void ParticleSystemAttributes::set_spawn_range(const Vector3 &range, long tm)
  32.113 +{
  32.114 +	psys_set_value3(&psattr->spawn_range, ANM_MSEC2TM(tm), v3_cons(range.x, range.y, range.z));
  32.115 +}
  32.116 +
  32.117 +void ParticleSystemAttributes::set_spawn_rate(float rate, long tm)
  32.118 +{
  32.119 +	psys_set_value(&psattr->rate, ANM_MSEC2TM(tm), rate);
  32.120 +}
  32.121 +
  32.122 +float ParticleSystemAttributes::get_spawn_rate(long tm) const
  32.123 +{
  32.124 +	return psys_get_value(&psattr->rate, ANM_MSEC2TM(tm));
  32.125 +}
  32.126 +
  32.127 +void ParticleSystemAttributes::set_life(float life, float range, long tm)
  32.128 +{
  32.129 +	psys_set_anm_rnd(&psattr->life, ANM_MSEC2TM(tm), life, range);
  32.130 +}
  32.131 +
  32.132 +void ParticleSystemAttributes::set_size(float sz, float range, long tm)
  32.133 +{
  32.134 +	psys_set_anm_rnd(&psattr->size, ANM_MSEC2TM(tm), sz, range);
  32.135 +}
  32.136 +
  32.137 +void ParticleSystemAttributes::set_spawn_dir(const Vector3 &dir, const Vector3 &range, long tm)
  32.138 +{
  32.139 +	psys_set_anm_rnd3(&psattr->dir, ANM_MSEC2TM(tm), v3_cons(dir.x, dir.y, dir.z), v3_cons(range.x, range.y, range.z));
  32.140 +}
  32.141 +
  32.142 +void ParticleSystemAttributes::set_gravity(const Vector3 &grav, long tm)
  32.143 +{
  32.144 +	psys_set_value3(&psattr->grav, ANM_MSEC2TM(tm), v3_cons(grav.x, grav.y, grav.z));
  32.145 +}
  32.146 +
  32.147 +void ParticleSystemAttributes::set_drag(float drag)
  32.148 +{
  32.149 +	psattr->drag = drag;
  32.150 +}
  32.151 +
  32.152 +void ParticleSystemAttributes::set_particle_limit(int lim)
  32.153 +{
  32.154 +	psattr->max_particles = lim;
  32.155 +}
  32.156 +
  32.157 +
  32.158 +// ---- ParticleSystem ----
  32.159 +
  32.160 +ParticleSystem::ParticleSystem()
  32.161 +	: attr(&psys.attr)
  32.162 +{
  32.163 +	psys_init(&psys);
  32.164 +	psys_draw_func(&psys, pdraw, pdraw_start, pdraw_end, (void*)this);
  32.165 +	start_time = LONG_MIN;
  32.166 +	last_upd_time = LONG_MIN;
  32.167 +}
  32.168 +
  32.169 +ParticleSystem::~ParticleSystem()
  32.170 +{
  32.171 +	psys_destroy(&psys);
  32.172 +}
  32.173 +
  32.174 +void ParticleSystem::set_start_time(long tm)
  32.175 +{
  32.176 +	start_time = tm;
  32.177 +}
  32.178 +
  32.179 +bool ParticleSystem::is_active() const
  32.180 +{
  32.181 +	float rate = attr.get_spawn_rate(last_upd_time);
  32.182 +	return psys.pcount > 0 || last_upd_time == 0;// || rate > 0.0;
  32.183 +}
  32.184 +
  32.185 +ParticleSystemAttributes *ParticleSystem::get_attr()
  32.186 +{
  32.187 +	return &attr;
  32.188 +}
  32.189 +
  32.190 +const ParticleSystemAttributes *ParticleSystem::get_attr() const
  32.191 +{
  32.192 +	return &attr;
  32.193 +}
  32.194 +
  32.195 +void ParticleSystem::set_attr(const ParticleSystemAttributes &pattr)
  32.196 +{
  32.197 +	attr = pattr;
  32.198 +}
  32.199 +
  32.200 +bool ParticleSystem::load(const char *fname)
  32.201 +{
  32.202 +	psys_texture_loader(psys_load_texture, 0, &attr);
  32.203 +	return attr.load(fname);
  32.204 +}
  32.205 +
  32.206 +bool ParticleSystem::save(const char *fname) const
  32.207 +{
  32.208 +	return attr.save(fname);
  32.209 +}
  32.210 +
  32.211 +void ParticleSystem::update(long tm)
  32.212 +{
  32.213 +	if(start_time > LONG_MIN) {
  32.214 +		tm -= start_time;
  32.215 +	}
  32.216 +
  32.217 +	Matrix4x4 xform;
  32.218 +	get_xform(tm, &xform);
  32.219 +
  32.220 +	Vector3 pos = Vector3(0, 0, 0).transformed(xform);
  32.221 +
  32.222 +	psys_set_pos(&psys, v3_cons(pos.x, pos.y, pos.z), 0);
  32.223 +	psys_update(&psys, (double)tm / 1000.0);
  32.224 +
  32.225 +	last_upd_time = tm;
  32.226 +}
  32.227 +
  32.228 +void ParticleSystem::draw() const
  32.229 +{
  32.230 +	psys_draw(&psys);
  32.231 +}
  32.232 +
  32.233 +// ---- particle drawing ----
  32.234 +struct PVertex {
  32.235 +	Vector4 color;
  32.236 +	Vector3 pos;
  32.237 +	Vector2 texcoord;
  32.238 +};
  32.239 +
  32.240 +
  32.241 +#define USE_VBO
  32.242 +#define USE_IBO
  32.243 +
  32.244 +
  32.245 +#define MAX_DRAW_PART	256
  32.246 +#define MAX_PVERTS		(MAX_DRAW_PART * 4)
  32.247 +static PVertex *pvarr, *pvptr;
  32.248 +
  32.249 +// double-buffered vbo set, write on one, while drawing from the other
  32.250 +
  32.251 +#ifdef USE_VBO
  32.252 +static unsigned int vbo[2];
  32.253 +static int cur_buf;		// current write vbo
  32.254 +#endif
  32.255 +static int num_buffered;	// number of particles bufferd, will flush when >= MAX_DRAW_PART
  32.256 +
  32.257 +// ok so the index array is constant, regardless of the particle system
  32.258 +// so this is a static index buffer created in init_particle_draw which should
  32.259 +// be called once.
  32.260 +#define MAX_PVIDX		(MAX_DRAW_PART * 6)
  32.261 +#ifdef USE_IBO
  32.262 +static unsigned int ibo;
  32.263 +#endif
  32.264 +unsigned int *pvidx;
  32.265 +
  32.266 +static ShaderProg *psdr;	// particle shader
  32.267 +static Texture2D *blank_tex;
  32.268 +
  32.269 +static inline void init_particle_draw()
  32.270 +{
  32.271 +	static bool done_init;
  32.272 +	if(done_init) {
  32.273 +		return;		// once
  32.274 +	}
  32.275 +
  32.276 +	pvidx = new unsigned int[MAX_PVIDX];
  32.277 +	unsigned int *ptr = pvidx;
  32.278 +
  32.279 +	static const unsigned int idxoffs[] = { 0, 1, 2, 0, 2, 3 };
  32.280 +
  32.281 +	for(int i=0; i<MAX_DRAW_PART; i++) {
  32.282 +		for(int j=0; j<6; j++) {
  32.283 +			*ptr++ = i * 4 + idxoffs[j];
  32.284 +		}
  32.285 +	}
  32.286 +
  32.287 +#ifdef USE_IBO
  32.288 +	glGenBuffers(1, &ibo);
  32.289 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  32.290 +	glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_PVIDX * sizeof *pvidx, pvidx, GL_STATIC_DRAW);
  32.291 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  32.292 +
  32.293 +	delete [] pvidx;
  32.294 +#endif
  32.295 +
  32.296 +#ifdef USE_VBO
  32.297 +	// create the stream vertex buffers (double buffering)
  32.298 +	glGenBuffers(2, vbo);
  32.299 +	for(int i=0; i<2; i++) {
  32.300 +		glBindBuffer(GL_ARRAY_BUFFER, vbo[i]);
  32.301 +		glBufferData(GL_ARRAY_BUFFER, MAX_PVERTS * sizeof(PVertex), 0, GL_STREAM_DRAW);
  32.302 +	}
  32.303 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  32.304 +#else
  32.305 +	pvarr = new PVertex[MAX_PVERTS];
  32.306 +	pvptr = pvarr;
  32.307 +#endif
  32.308 +
  32.309 +	// load shader program
  32.310 +	if(!(psdr = get_sdrprog("psdr.v.glsl", "psdr.p.glsl"))) {
  32.311 +		error_log("failed to load particle shader!\n");
  32.312 +	}
  32.313 +
  32.314 +	// create empty texture
  32.315 +	Image *img = texgen_solid(8, 8, Vector4(1, 1, 1, 1));
  32.316 +	blank_tex = new Texture2D;
  32.317 +	blank_tex->set_image(*img);
  32.318 +	delete img;
  32.319 +
  32.320 +	done_init = true;
  32.321 +}
  32.322 +
  32.323 +static void pdraw_flush()
  32.324 +{
  32.325 +#ifdef USE_VBO
  32.326 +	// assuming vbo[cur_buf] is bound
  32.327 +	glUnmapBuffer(GL_ARRAY_BUFFER);
  32.328 +#endif
  32.329 +
  32.330 +	// draw from the bound buffer 6 indices per particle
  32.331 +#ifdef USE_IBO
  32.332 +	glDrawElements(GL_TRIANGLES, num_buffered * 6, GL_UNSIGNED_INT, 0);
  32.333 +#else
  32.334 +	glDrawElements(GL_TRIANGLES, num_buffered * 6, GL_UNSIGNED_INT, pvidx);
  32.335 +#endif
  32.336 +	num_buffered = 0;
  32.337 +
  32.338 +#ifdef USE_VBO
  32.339 +	// map the next buffer (write buffer) while the previous is drawing
  32.340 +	cur_buf = (cur_buf + 1) & 1;
  32.341 +	glBindBuffer(GL_ARRAY_BUFFER, vbo[cur_buf]);
  32.342 +	pvarr = (PVertex*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
  32.343 +#endif
  32.344 +	pvptr = pvarr;
  32.345 +}
  32.346 +
  32.347 +static void pdraw_start(const psys_emitter *em, void *cls)
  32.348 +{
  32.349 +	ParticleSystem *ps = (ParticleSystem*)cls;
  32.350 +
  32.351 +	init_particle_draw();
  32.352 +
  32.353 +	num_buffered = 0;
  32.354 +
  32.355 +#ifdef USE_IBO
  32.356 +	// bind the particle index buffer which is static
  32.357 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  32.358 +#endif
  32.359 +
  32.360 +#ifdef USE_VBO
  32.361 +	// map the current write buffer
  32.362 +	glBindBuffer(GL_ARRAY_BUFFER, vbo[cur_buf]);
  32.363 +	pvarr = (PVertex*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
  32.364 +#endif
  32.365 +	pvptr = pvarr;
  32.366 +
  32.367 +	Texture *tex = ps->get_attr()->get_texture();
  32.368 +	if(tex) {
  32.369 +		tex->bind();
  32.370 +	} else {
  32.371 +		blank_tex->bind();
  32.372 +	}
  32.373 +	psdr->bind();
  32.374 +
  32.375 +	glDisable(GL_DEPTH_TEST);
  32.376 +	glDisable(GL_CULL_FACE);
  32.377 +	glEnable(GL_BLEND);
  32.378 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  32.379 +	glDepthMask(0);
  32.380 +
  32.381 +	glEnableVertexAttribArray(MESH_ATTR_VERTEX);
  32.382 +	glEnableVertexAttribArray(MESH_ATTR_COLOR);
  32.383 +	glEnableVertexAttribArray(MESH_ATTR_TEXCOORD);
  32.384 +
  32.385 +#ifdef USE_VBO
  32.386 +	glVertexAttribPointer(MESH_ATTR_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof *pvarr, (void*)((char*)&pvarr->pos - (char*)pvarr));
  32.387 +	glVertexAttribPointer(MESH_ATTR_COLOR, 4, GL_FLOAT, GL_TRUE, sizeof *pvarr, (void*)((char*)&pvarr->color - (char*)pvarr));
  32.388 +	glVertexAttribPointer(MESH_ATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof *pvarr, (void*)((char*)&pvarr->texcoord - (char*)pvarr));
  32.389 +#else
  32.390 +	glVertexAttribPointer(MESH_ATTR_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof *pvarr, (void*)&pvarr->pos);
  32.391 +	glVertexAttribPointer(MESH_ATTR_COLOR, 4, GL_FLOAT, GL_TRUE, sizeof *pvarr, (void*)&pvarr->color);
  32.392 +	glVertexAttribPointer(MESH_ATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof *pvarr, (void*)&pvarr->texcoord);
  32.393 +#endif
  32.394 +}
  32.395 +
  32.396 +static void pdraw(const psys_emitter *em, const psys_particle *part, void *cls)
  32.397 +{
  32.398 +	ParticleSystem *ps = (ParticleSystem*)cls;
  32.399 +
  32.400 +	static const Vector3 pv[] = {
  32.401 +		Vector3(-0.5, -0.5, 0),
  32.402 +		Vector3(0.5, -0.5, 0),
  32.403 +		Vector3(0.5, 0.5, 0),
  32.404 +		Vector3(-0.5, 0.5, 0)
  32.405 +	};
  32.406 +	static const Vector2 tex[] = {
  32.407 +		Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)
  32.408 +	};
  32.409 +	Vector4 color = Vector4(part->color.x, part->color.y, part->color.z, part->alpha);
  32.410 +
  32.411 +	for(int i=0; i<4; i++) {
  32.412 +		pvptr->color = color;
  32.413 +		pvptr->pos = pv[i] * part->size + part->pos;
  32.414 +		pvptr->texcoord = tex[i];
  32.415 +		pvptr++;
  32.416 +	}
  32.417 +	// XXX we don't need billboarding for this game, so don't bother
  32.418 +
  32.419 +	// if we reached the maximum number of buffered particles, draw them
  32.420 +	if(++num_buffered >= MAX_DRAW_PART) {
  32.421 +		pdraw_flush();	// this will reset the counter
  32.422 +	}
  32.423 +}
  32.424 +
  32.425 +static void pdraw_end(const psys_emitter *em, void *cls)
  32.426 +{
  32.427 +	// if we have leftover particles buffered, draw them before returning
  32.428 +	if(num_buffered) {
  32.429 +		pdraw_flush();
  32.430 +	}
  32.431 +
  32.432 +	// cleanup
  32.433 +	glDisableVertexAttribArray(MESH_ATTR_VERTEX);
  32.434 +	glDisableVertexAttribArray(MESH_ATTR_COLOR);
  32.435 +	glDisableVertexAttribArray(MESH_ATTR_TEXCOORD);
  32.436 +
  32.437 +#ifdef USE_VBO
  32.438 +	glUnmapBuffer(GL_ARRAY_BUFFER);
  32.439 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  32.440 +#endif
  32.441 +#ifdef USE_IBO
  32.442 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  32.443 +#endif
  32.444 +
  32.445 +	glDepthMask(1);
  32.446 +	glDisable(GL_BLEND);
  32.447 +
  32.448 +	glEnable(GL_DEPTH_TEST);
  32.449 +	glEnable(GL_CULL_FACE);
  32.450 +}
  32.451 +
  32.452 +static unsigned int psys_load_texture(const char *fname, void *cls)
  32.453 +{
  32.454 +	ParticleSystemAttributes *attr = (ParticleSystemAttributes*)cls;
  32.455 +
  32.456 +	Texture *tex = texset.get(fname);
  32.457 +	if(tex) {
  32.458 +		attr->set_texture(tex);
  32.459 +		return tex->get_id();
  32.460 +	}
  32.461 +	return 0;
  32.462 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/src/psyspp.h	Thu Nov 14 05:27:09 2013 +0200
    33.3 @@ -0,0 +1,79 @@
    33.4 +#ifndef PSYSPP_H_
    33.5 +#define PSYSPP_H_
    33.6 +
    33.7 +#include "xform_node.h"
    33.8 +#include "texture.h"
    33.9 +#include <psys/psys.h>
   33.10 +
   33.11 +class ParticleSystemAttributes {
   33.12 +private:
   33.13 +	Texture *tex;
   33.14 +	psys_attributes *psattr;
   33.15 +	bool own_psattr;
   33.16 +
   33.17 +public:
   33.18 +	ParticleSystemAttributes();
   33.19 +	ParticleSystemAttributes(psys_attributes *psattr);
   33.20 +	~ParticleSystemAttributes();
   33.21 +
   33.22 +	ParticleSystemAttributes(const ParticleSystemAttributes &rhs);
   33.23 +	ParticleSystemAttributes &operator =(const ParticleSystemAttributes &rhs);
   33.24 +
   33.25 +	bool load(const char *fname);
   33.26 +	bool load(FILE *fp);
   33.27 +	bool save(const char *fname) const;
   33.28 +	bool save(FILE *fp) const;
   33.29 +
   33.30 +	// particle attributes
   33.31 +	void set_part_color(const Vector3 &color, float t = 0);
   33.32 +	void set_part_alpha(float alpha, float t = 0);
   33.33 +	void set_part_scale(float size, float t = 0);
   33.34 +
   33.35 +	// emmiter attributes
   33.36 +	void set_texture(Texture *tex);
   33.37 +	Texture *get_texture() const;
   33.38 +
   33.39 +	void set_spawn_range(const Vector3 &range, long tm = 0);
   33.40 +
   33.41 +	void set_spawn_rate(float rate, long tm = 0);
   33.42 +	float get_spawn_rate(long tm = 0) const;
   33.43 +
   33.44 +	void set_life(float life, float range = 0.0, long tm = 0);
   33.45 +	void set_size(float sz, float range = 0.0, long tm = 0);
   33.46 +	void set_spawn_dir(const Vector3 &dir, const Vector3 &range = Vector3(0, 0, 0), long tm = 0);
   33.47 +
   33.48 +	void set_gravity(const Vector3 &grav, long tm = 0);
   33.49 +	void set_drag(float drag);
   33.50 +
   33.51 +	void set_particle_limit(int lim);
   33.52 +};
   33.53 +
   33.54 +class ParticleSystem : public XFormNode {
   33.55 +private:
   33.56 +	psys_emitter psys;
   33.57 +	ParticleSystemAttributes attr;
   33.58 +
   33.59 +	long start_time;	// subtracted from all time calculations
   33.60 +	long last_upd_time;
   33.61 +
   33.62 +public:
   33.63 +	ParticleSystem();
   33.64 +	~ParticleSystem();
   33.65 +
   33.66 +	void set_start_time(long tm);
   33.67 +
   33.68 +	bool is_active() const;
   33.69 +
   33.70 +	ParticleSystemAttributes *get_attr();
   33.71 +	const ParticleSystemAttributes *get_attr() const;
   33.72 +
   33.73 +	void set_attr(const ParticleSystemAttributes &pattr);
   33.74 +
   33.75 +	bool load(const char *fname);
   33.76 +	bool save(const char *fname) const;
   33.77 +
   33.78 +	void update(long tm);
   33.79 +	void draw() const;
   33.80 +};
   33.81 +
   33.82 +#endif	// PSYSPP_H_
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/src/rtarg.cc	Thu Nov 14 05:27:09 2013 +0200
    34.3 @@ -0,0 +1,259 @@
    34.4 +#include <stack>
    34.5 +#include "rtarg.h"
    34.6 +#include "texture.h"
    34.7 +#include "logger.h"
    34.8 +
    34.9 +RenderTarget::RenderTarget()
   34.10 +{
   34.11 +	width = height = 0;
   34.12 +	fbo = 0;
   34.13 +	rbuf_zstencil = 0;
   34.14 +	color_tex = 0;
   34.15 +	tex_face = 0;
   34.16 +	tex_targ = 0;
   34.17 +}
   34.18 +
   34.19 +RenderTarget::~RenderTarget()
   34.20 +{
   34.21 +	cleanup();
   34.22 +}
   34.23 +
   34.24 +bool RenderTarget::create(unsigned int fmt)
   34.25 +{
   34.26 +	int vp[4];
   34.27 +	glGetIntegerv(GL_VIEWPORT, vp);
   34.28 +
   34.29 +	return create(vp[2] - vp[0], vp[3] - vp[1], fmt);
   34.30 +}
   34.31 +
   34.32 +bool RenderTarget::create(int width, int height, unsigned int fmt)
   34.33 +{
   34.34 +	debug_log("RenderTarget::create(%d, %d)\n", width, height);
   34.35 +	cleanup();
   34.36 +
   34.37 +	tex_targ = GL_TEXTURE_2D;
   34.38 +	this->width = width;
   34.39 +	this->height = height;
   34.40 +	int tex_width = next_pow2(width);
   34.41 +	int tex_height = next_pow2(height);
   34.42 +
   34.43 +	CHECKGLERR;
   34.44 +	color_tex = new Texture2D;
   34.45 +	color_tex->create(tex_width, tex_height, fmt);
   34.46 +	CHECKGLERR;
   34.47 +	tex_face = 0;
   34.48 +
   34.49 +	glGenFramebuffers(1, &fbo);
   34.50 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
   34.51 +
   34.52 +	glBindTexture(GL_TEXTURE_2D, color_tex->get_id());
   34.53 +	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_tex->get_id(), 0);
   34.54 +	glBindTexture(GL_TEXTURE_2D, 0);
   34.55 +
   34.56 +	glGenRenderbuffers(1, &rbuf_zstencil);
   34.57 +	glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil);
   34.58 +	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tex_width, tex_height);
   34.59 +	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil);
   34.60 +	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil);
   34.61 +
   34.62 +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
   34.63 +	CHECKGLERR;
   34.64 +	return true;
   34.65 +}
   34.66 +
   34.67 +bool RenderTarget::create(Texture *tex, int face)
   34.68 +{
   34.69 +	debug_log("RenderTarget::create(tex{%d, %d}, face:%d)\n", tex->get_size(0),
   34.70 +			tex->get_size(1), face);
   34.71 +
   34.72 +	tex_targ = GL_TEXTURE_2D;
   34.73 +	if(dynamic_cast<TextureCube*>(tex)) {
   34.74 +		if(face >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
   34.75 +			tex_targ = face;
   34.76 +		} else if(face >= 0 && face < 6) {
   34.77 +			tex_targ = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
   34.78 +		} else {
   34.79 +			error_log("invalid face (%d) passed to RenderTarget::create(TextureCube*, int)\n", face);
   34.80 +			return false;
   34.81 +		}
   34.82 +	}
   34.83 +
   34.84 +	cleanup();
   34.85 +
   34.86 +	width = tex->get_size(0);
   34.87 +	height = tex->get_size(1);
   34.88 +
   34.89 +	color_tex = tex;
   34.90 +
   34.91 +	glGenFramebuffers(1, &fbo);
   34.92 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
   34.93 +
   34.94 +	glBindTexture(tex_targ, color_tex->get_id());
   34.95 +	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_targ, color_tex->get_id(), 0);
   34.96 +	glBindTexture(tex_targ, 0);
   34.97 +
   34.98 +	glGenRenderbuffers(1, &rbuf_zstencil);
   34.99 +	glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil);
  34.100 +	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
  34.101 +	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil);
  34.102 +	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil);
  34.103 +
  34.104 +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
  34.105 +	CHECKGLERR;
  34.106 +	return true;
  34.107 +}
  34.108 +
  34.109 +void RenderTarget::cleanup()
  34.110 +{
  34.111 +	delete color_tex;
  34.112 +	color_tex = 0;
  34.113 +
  34.114 +	if(fbo) {
  34.115 +		glDeleteFramebuffers(1, &fbo);
  34.116 +	}
  34.117 +	if(rbuf_zstencil) {
  34.118 +		glDeleteRenderbuffers(1, &rbuf_zstencil);
  34.119 +	}
  34.120 +
  34.121 +	fbo = rbuf_zstencil = 0;
  34.122 +	width = height = 0;
  34.123 +	tex_face = 0;
  34.124 +	tex_targ = 0;
  34.125 +}
  34.126 +
  34.127 +bool RenderTarget::resize(int width, int height)
  34.128 +{
  34.129 +	this->width = width;
  34.130 +	this->height = height;
  34.131 +	int tex_width = next_pow2(width);
  34.132 +	int tex_height = next_pow2(height);
  34.133 +
  34.134 +	debug_log("resizing render target (fbo %u): %dx%d [%dx%d]\n", fbo, width, height, tex_width, tex_height);
  34.135 +
  34.136 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
  34.137 +
  34.138 +	color_tex->create(tex_width, tex_height, color_tex->get_format());
  34.139 +	color_tex->bind();
  34.140 +	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_targ, color_tex->get_id(), 0);
  34.141 +	glBindTexture(tex_targ, 0);
  34.142 +
  34.143 +	glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil);
  34.144 +	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tex_width, tex_height);
  34.145 +
  34.146 +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
  34.147 +	return true;
  34.148 +}
  34.149 +
  34.150 +int RenderTarget::get_width() const
  34.151 +{
  34.152 +	return width;
  34.153 +}
  34.154 +
  34.155 +int RenderTarget::get_height() const
  34.156 +{
  34.157 +	return height;
  34.158 +}
  34.159 +
  34.160 +Texture *RenderTarget::get_texture() const
  34.161 +{
  34.162 +	return color_tex;
  34.163 +}
  34.164 +
  34.165 +Matrix4x4 RenderTarget::get_texture_matrix() const
  34.166 +{
  34.167 +	float sx = (float)width / (float)color_tex->get_size(0);
  34.168 +	float sy = (float)height / (float)color_tex->get_size(1);
  34.169 +
  34.170 +	// counting on RVO to optimize this away
  34.171 +	return Matrix4x4(sx, 0, 0, 0,
  34.172 +					0, sy, 0, 0,
  34.173 +					0, 0, 1, 0,
  34.174 +					0, 0, 0, 1);
  34.175 +}
  34.176 +
  34.177 +
  34.178 +static const char *fbstname[] = {
  34.179 +	"GL_FRAMEBUFFER_COMPLETE",
  34.180 +	"GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
  34.181 +	"GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
  34.182 +	"no such fbo error",
  34.183 +	"GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
  34.184 +	"GL_FRAMEBUFFER_INCOMPLETE_FORMATS",
  34.185 +	"GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
  34.186 +	"GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
  34.187 +	"GL_FRAMEBUFFER_UNSUPPORTED"
  34.188 +};
  34.189 +
  34.190 +bool RenderTarget::check() const
  34.191 +{
  34.192 +	bool res = true;
  34.193 +
  34.194 +#ifndef GL_ES_VERSION_2_0
  34.195 +	int prev_fb = 0;
  34.196 +	glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prev_fb);
  34.197 +#endif
  34.198 +
  34.199 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
  34.200 +
  34.201 +	int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  34.202 +	if(status != GL_FRAMEBUFFER_COMPLETE) {
  34.203 +		error_log("RenderTarget::check: incomplete FBO %u: %s\n", fbo,
  34.204 +				fbstname[status - GL_FRAMEBUFFER_COMPLETE]);
  34.205 +		res = false;
  34.206 +		goto end;
  34.207 +	}
  34.208 +
  34.209 +end:
  34.210 +#ifndef GL_ES_VERSION_2_0
  34.211 +	glBindFramebuffer(GL_FRAMEBUFFER, prev_fb);
  34.212 +#endif
  34.213 +	return res;
  34.214 +}
  34.215 +
  34.216 +void RenderTarget::bind() const
  34.217 +{
  34.218 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
  34.219 +
  34.220 +	glViewport(0, 0, width, height);
  34.221 +}
  34.222 +
  34.223 +struct Viewport { int vp[4]; };
  34.224 +static std::stack<Viewport> vpstack;
  34.225 +
  34.226 +void set_render_target(const RenderTarget *rtarg)
  34.227 +{
  34.228 +	Viewport vp;
  34.229 +
  34.230 +	if(rtarg) {
  34.231 +		glGetIntegerv(GL_VIEWPORT, vp.vp);
  34.232 +		vpstack.push(vp);
  34.233 +
  34.234 +		rtarg->bind();
  34.235 +	} else {
  34.236 +#ifdef GL_ES_VERSION_2_0
  34.237 +		extern unsigned int default_fbo;
  34.238 +		glBindFramebuffer(GL_FRAMEBUFFER, default_fbo);
  34.239 +#else
  34.240 +		glBindFramebuffer(GL_FRAMEBUFFER, 0);
  34.241 +#endif
  34.242 +
  34.243 +		if(vpstack.empty()) {
  34.244 +			return;
  34.245 +		}
  34.246 +		vp = vpstack.top();
  34.247 +		vpstack.pop();
  34.248 +		glViewport(vp.vp[0], vp.vp[1], vp.vp[2], vp.vp[3]);
  34.249 +	}
  34.250 +}
  34.251 +
  34.252 +int next_pow2(int x)
  34.253 +{
  34.254 +	x--;
  34.255 +	x = (x >> 1) | x;
  34.256 +	x = (x >> 2) | x;
  34.257 +	x = (x >> 4) | x;
  34.258 +	x = (x >> 8) | x;
  34.259 +	x = (x >> 16) | x;
  34.260 +	return x + 1;
  34.261 +}
  34.262 +
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/src/rtarg.h	Thu Nov 14 05:27:09 2013 +0200
    35.3 @@ -0,0 +1,49 @@
    35.4 +#ifndef RTARG_H_
    35.5 +#define RTARG_H_
    35.6 +
    35.7 +#include "vmath/vmath.h"
    35.8 +#include "opengl.h"
    35.9 +
   35.10 +class Texture;
   35.11 +
   35.12 +class RenderTarget {
   35.13 +private:
   35.14 +	int width, height;
   35.15 +
   35.16 +	unsigned int fbo;
   35.17 +	Texture *color_tex;
   35.18 +	unsigned int tex_targ;
   35.19 +	int tex_face;
   35.20 +	unsigned int rbuf_zstencil;
   35.21 +
   35.22 +public:
   35.23 +	RenderTarget();
   35.24 +	~RenderTarget();
   35.25 +
   35.26 +	bool create(unsigned int fmt = GL_RGBA);
   35.27 +	bool create(int width, int height, unsigned int fmt = GL_RGBA);
   35.28 +	bool create(Texture *tex, int face = 0);
   35.29 +
   35.30 +	void cleanup();
   35.31 +
   35.32 +	bool resize(int width, int height);
   35.33 +
   35.34 +	int get_width() const;
   35.35 +	int get_height() const;
   35.36 +
   35.37 +	Texture *get_texture() const;
   35.38 +
   35.39 +	/** calculates a texture matrix to map the full texture space
   35.40 +	 * onto the part of the texture occupied by the render target
   35.41 +	 */
   35.42 +	Matrix4x4 get_texture_matrix() const;
   35.43 +
   35.44 +	bool check() const;
   35.45 +	void bind() const;
   35.46 +};
   35.47 +
   35.48 +void set_render_target(const RenderTarget *rtarg);
   35.49 +
   35.50 +int next_pow2(int x);
   35.51 +
   35.52 +#endif	// RTARG_H_
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/src/scene.cc	Thu Nov 14 05:27:09 2013 +0200
    36.3 @@ -0,0 +1,39 @@
    36.4 +#include "scene.h"
    36.5 +#include "opengl.h"
    36.6 +
    36.7 +Scene::~Scene()
    36.8 +{
    36.9 +	destroy();
   36.10 +}
   36.11 +
   36.12 +void Scene::destroy()
   36.13 +{
   36.14 +	for(size_t i=0; i<objects.size(); i++) {
   36.15 +		delete objects[i];
   36.16 +	}
   36.17 +	objects.clear();
   36.18 +
   36.19 +	for(size_t i=0; i<meshes.size(); i++) {
   36.20 +		delete meshes[i];
   36.21 +	}
   36.22 +	meshes.clear();
   36.23 +
   36.24 +	for(size_t i=0; i<curves.size(); i++) {
   36.25 +		delete curves[i];
   36.26 +	}
   36.27 +	curves.clear();
   36.28 +}
   36.29 +
   36.30 +void Scene::draw(long msec) const
   36.31 +{
   36.32 +	for(size_t i=0; i<objects.size(); i++) {
   36.33 +		objects[i]->draw(msec);
   36.34 +	}
   36.35 +
   36.36 +	if(objects.empty()) {
   36.37 +		printf("rendering meshes directly\n");
   36.38 +		for(size_t i=0; i<meshes.size(); i++) {
   36.39 +			meshes[i]->draw();
   36.40 +		}
   36.41 +	}
   36.42 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/src/scene.h	Thu Nov 14 05:27:09 2013 +0200
    37.3 @@ -0,0 +1,20 @@
    37.4 +#ifndef SCENE_H_
    37.5 +#define SCENE_H_
    37.6 +
    37.7 +#include <vector>
    37.8 +#include "object.h"
    37.9 +#include "curve.h"
   37.10 +
   37.11 +class Scene {
   37.12 +public:
   37.13 +	std::vector<Object*> objects;
   37.14 +	std::vector<Mesh*> meshes;
   37.15 +	std::vector<Curve*> curves;
   37.16 +
   37.17 +	~Scene();
   37.18 +	void destroy();
   37.19 +
   37.20 +	void draw(long msec = 0) const;
   37.21 +};
   37.22 +
   37.23 +#endif	// SCENE_H_
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/src/sdrman.cc	Thu Nov 14 05:27:09 2013 +0200
    38.3 @@ -0,0 +1,27 @@
    38.4 +#include "sdrman.h"
    38.5 +
    38.6 +ShaderSet vsdrset(GL_VERTEX_SHADER);
    38.7 +ShaderSet psdrset(GL_FRAGMENT_SHADER);
    38.8 +
    38.9 +ShaderProg *get_sdrprog(const char *vname, const char *pname)
   38.10 +{
   38.11 +	Shader *vsdr = vname ? vsdrset.get(vname) : 0;
   38.12 +	Shader *psdr = pname ? psdrset.get(pname) : 0;
   38.13 +
   38.14 +	if(vname && !vsdr) {
   38.15 +		return 0;
   38.16 +	}
   38.17 +	if(pname && !psdr) {
   38.18 +		return 0;
   38.19 +	}
   38.20 +	if(!vsdr && !psdr) {
   38.21 +		return 0;
   38.22 +	}
   38.23 +
   38.24 +	ShaderProg *prog = new ShaderProg;
   38.25 +	if(!prog->create(vsdr, psdr)) {
   38.26 +		delete prog;
   38.27 +		return 0;
   38.28 +	}
   38.29 +	return prog;
   38.30 +}
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/src/sdrman.h	Thu Nov 14 05:27:09 2013 +0200
    39.3 @@ -0,0 +1,11 @@
    39.4 +#ifndef SDRMAN_H_
    39.5 +#define SDRMAN_H_
    39.6 +
    39.7 +#include "shader.h"
    39.8 +
    39.9 +extern ShaderSet vsdrset;
   39.10 +extern ShaderSet psdrset;
   39.11 +
   39.12 +ShaderProg *get_sdrprog(const char *vname, const char *pname);
   39.13 +
   39.14 +#endif	// SDRMAN_H_
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/src/shader.cc	Thu Nov 14 05:27:09 2013 +0200
    40.3 @@ -0,0 +1,641 @@
    40.4 +#include <stdio.h>
    40.5 +#include <string.h>
    40.6 +#include <stdarg.h>
    40.7 +#include <errno.h>
    40.8 +#include "opengl.h"
    40.9 +#include "shader.h"
   40.10 +#include "logger.h"
   40.11 +#include "unistate.h"
   40.12 +#include "mesh.h"
   40.13 +
   40.14 +#ifdef _MSC_VER
   40.15 +#include <malloc.h>
   40.16 +#else
   40.17 +#include <alloca.h>
   40.18 +#endif
   40.19 +
   40.20 +#ifdef __GLEW_H__
   40.21 +#define HAVE_GEOMETRY_SHADER
   40.22 +#define HAVE_TESSELATION_SHADER
   40.23 +#endif
   40.24 +
   40.25 +static void bind_standard_attr(const ShaderProg *prog);
   40.26 +static const char *strtype(unsigned int type);
   40.27 +
   40.28 +ShaderProg *ShaderProg::current;
   40.29 +
   40.30 +Shader::Shader()
   40.31 +{
   40.32 +	sdr = type = 0;
   40.33 +	name = 0;
   40.34 +}
   40.35 +
   40.36 +Shader::~Shader()
   40.37 +{
   40.38 +	destroy();
   40.39 +}
   40.40 +
   40.41 +unsigned int Shader::get_id() const
   40.42 +{
   40.43 +	return sdr;
   40.44 +}
   40.45 +
   40.46 +void Shader::set_name(const char *name)
   40.47 +{
   40.48 +	delete [] this->name;
   40.49 +	this->name = new char[strlen(name) + 1];
   40.50 +	strcpy(this->name, name);
   40.51 +}
   40.52 +
   40.53 +const char *Shader::get_name() const
   40.54 +{
   40.55 +	return name;
   40.56 +}
   40.57 +
   40.58 +bool Shader::create(const char *src, unsigned int type)
   40.59 +{
   40.60 +#if !GL_ES_VERSION_2_0
   40.61 +	const char *src_arr[] = {src};
   40.62 +#else
   40.63 +	const char *src_arr[] = { "precision mediump float; ", src };
   40.64 +#endif
   40.65 +
   40.66 +	if(!sdr) {
   40.67 +		sdr = glCreateShader(type);
   40.68 +	}
   40.69 +
   40.70 +	info_log("compiling shader: %s... ", name ? name : "");
   40.71 +
   40.72 +	glShaderSource(sdr, sizeof src_arr / sizeof *src_arr, src_arr, 0);
   40.73 +	glCompileShader(sdr);
   40.74 +
   40.75 +	int status;
   40.76 +	glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
   40.77 +
   40.78 +	info_log(status ? "success\n" : "failed\n");
   40.79 +
   40.80 +	int info_len;
   40.81 +	glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
   40.82 +	if(info_len > 1) {
   40.83 +		char *buf = (char*)alloca(info_len);
   40.84 +		glGetShaderInfoLog(sdr, info_len, 0, buf);
   40.85 +		buf[info_len - 1] = 0;
   40.86 +
   40.87 +		if(status) {
   40.88 +			info_log("%s\n", buf);
   40.89 +		} else {
   40.90 +			error_log("%s\n", buf);
   40.91 +		}
   40.92 +	}
   40.93 +
   40.94 +	return status == GL_TRUE;
   40.95 +}
   40.96 +
   40.97 +void Shader::destroy()
   40.98 +{
   40.99 +	if(sdr) {
  40.100 +		glDeleteShader(sdr);
  40.101 +	}
  40.102 +	sdr = type = 0;
  40.103 +
  40.104 +	delete [] name;
  40.105 +	name = 0;
  40.106 +}
  40.107 +
  40.108 +bool Shader::load(const char *fname, unsigned int type)
  40.109 +{
  40.110 +	FILE *fp;
  40.111 +
  40.112 +	if(!(fp = fopen(fname, "rb"))) {
  40.113 +		error_log("failed to load %s shader: %s: %s\n", strtype(type), fname, strerror(errno));
  40.114 +		return false;
  40.115 +	}
  40.116 +
  40.117 +	fseek(fp, 0, SEEK_END);
  40.118 +	long sz = ftell(fp);
  40.119 +	rewind(fp);
  40.120 +
  40.121 +	char *src = (char*)alloca(sz + 1);
  40.122 +	if(fread(src, 1, sz, fp) < (size_t)sz) {
  40.123 +		error_log("failed to load %s shader: %s: %s\n", strtype(type), fname, strerror(errno));
  40.124 +		fclose(fp);
  40.125 +		return false;
  40.126 +	}
  40.127 +	src[sz] = 0;
  40.128 +	fclose(fp);
  40.129 +
  40.130 +	set_name(fname);
  40.131 +	return create(src, type);
  40.132 +}
  40.133 +
  40.134 +// ---- shader program ----
  40.135 +ShaderProg::ShaderProg()
  40.136 +{
  40.137 +	prog = 0;
  40.138 +	must_link = true;
  40.139 +}
  40.140 +
  40.141 +ShaderProg::~ShaderProg()
  40.142 +{
  40.143 +	destroy();
  40.144 +}
  40.145 +
  40.146 +unsigned int ShaderProg::get_id() const
  40.147 +{
  40.148 +	return prog;
  40.149 +}
  40.150 +
  40.151 +bool ShaderProg::create(const char *src, unsigned int type, ...)
  40.152 +{
  40.153 +	va_list ap;
  40.154 +
  40.155 +	va_start(ap, type);
  40.156 +	bool res = create(src, type, ap);
  40.157 +	va_end(ap);
  40.158 +
  40.159 +	return res;
  40.160 +}
  40.161 +
  40.162 +bool ShaderProg::create(const char *src, unsigned int type, va_list ap)
  40.163 +{
  40.164 +	destroy();
  40.165 +	prog = glCreateProgram();
  40.166 +
  40.167 +	while(src) {
  40.168 +		Shader *sdr = new Shader;
  40.169 +		if(!sdr->create(src, type)) {
  40.170 +			va_end(ap);
  40.171 +			return false;
  40.172 +		}
  40.173 +		add_shader(sdr);
  40.174 +		src = va_arg(ap, const char*);
  40.175 +		type = va_arg(ap, unsigned int);
  40.176 +	}
  40.177 +	return link();
  40.178 +}
  40.179 +
  40.180 +bool ShaderProg::create(const char *vsrc, const char *psrc)
  40.181 +{
  40.182 +	return create(VSDR(vsrc), PSDR(psrc), 0);
  40.183 +}
  40.184 +
  40.185 +bool ShaderProg::create(Shader *sdr, ...)
  40.186 +{
  40.187 +	va_list ap;
  40.188 +
  40.189 +	va_start(ap, sdr);
  40.190 +	bool res = create(sdr, ap);
  40.191 +	va_end(ap);
  40.192 +
  40.193 +	return res;
  40.194 +}
  40.195 +
  40.196 +bool ShaderProg::create(Shader *sdr, va_list ap)
  40.197 +{
  40.198 +	destroy();
  40.199 +	prog = glCreateProgram();
  40.200 +
  40.201 +	while(sdr) {
  40.202 +		add_shader(sdr);
  40.203 +		sdr = va_arg(ap, Shader*);
  40.204 +	}
  40.205 +	return link();
  40.206 +}
  40.207 +
  40.208 +bool ShaderProg::create(Shader *vsdr, Shader *psdr)
  40.209 +{
  40.210 +	return create(vsdr, psdr, 0);
  40.211 +}
  40.212 +
  40.213 +void ShaderProg::destroy()
  40.214 +{
  40.215 +	if(prog) {
  40.216 +		glDeleteProgram(prog);
  40.217 +	}
  40.218 +	prog = 0;
  40.219 +
  40.220 +	shaders.clear();
  40.221 +	// don't actually destroy the shaders, let the ShaderSet own them
  40.222 +}
  40.223 +
  40.224 +bool ShaderProg::load(const char *fname, unsigned int type, ...)
  40.225 +{
  40.226 +	va_list ap;
  40.227 +	va_start(ap, type);
  40.228 +	bool res = load(fname, type, ap);
  40.229 +	va_end(ap);
  40.230 +
  40.231 +	return res;
  40.232 +}
  40.233 +
  40.234 +bool ShaderProg::load(const char *fname, unsigned int type, va_list ap)
  40.235 +{
  40.236 +	destroy();
  40.237 +	prog = glCreateProgram();
  40.238 +
  40.239 +	while(fname) {
  40.240 +		Shader *sdr = new Shader;
  40.241 +		if(!sdr->load(fname, type)) {
  40.242 +			delete sdr;
  40.243 +			return false;
  40.244 +		}
  40.245 +		add_shader(sdr);
  40.246 +
  40.247 +		if((fname = va_arg(ap, const char*))) {
  40.248 +			type = va_arg(ap, unsigned int);
  40.249 +		}
  40.250 +	}
  40.251 +
  40.252 +	return link();
  40.253 +}
  40.254 +
  40.255 +bool ShaderProg::load(const char *vfname, const char *pfname)
  40.256 +{
  40.257 +	return load(VSDR(vfname), PSDR(pfname), 0);
  40.258 +}
  40.259 +
  40.260 +void ShaderProg::add_shader(Shader *sdr)
  40.261 +{
  40.262 +	glAttachShader(prog, sdr->get_id());
  40.263 +}
  40.264 +
  40.265 +bool ShaderProg::link() const
  40.266 +{
  40.267 +	bind_standard_attr(this);
  40.268 +
  40.269 +	CHECKGLERR;
  40.270 +	info_log("linking program ... ");
  40.271 +	glLinkProgram(prog);
  40.272 +
  40.273 +	int status;
  40.274 +	glGetProgramiv(prog, GL_LINK_STATUS, &status);
  40.275 +
  40.276 +	info_log(status ? "success\n" : "failed\n");
  40.277 +
  40.278 +	int info_len;
  40.279 +	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
  40.280 +	if(info_len > 1) {
  40.281 +		char *buf = (char*)alloca(info_len);
  40.282 +		glGetProgramInfoLog(prog, info_len, 0, buf);
  40.283 +		buf[info_len - 1] = 0;
  40.284 +
  40.285 +		if(status) {
  40.286 +			info_log("%s\n", buf);
  40.287 +		} else {
  40.288 +			error_log("%s\n", buf);
  40.289 +		}
  40.290 +	}
  40.291 +
  40.292 +	if(status) {
  40.293 +		must_link = false;
  40.294 +		cache_state_uniforms();
  40.295 +
  40.296 +		return true;
  40.297 +	}
  40.298 +	return false;
  40.299 +}
  40.300 +
  40.301 +void ShaderProg::bind() const
  40.302 +{
  40.303 +	CHECKGLERR;
  40.304 +	if(must_link) {
  40.305 +		if(!link()) {
  40.306 +			return;
  40.307 +		}
  40.308 +	}
  40.309 +	CHECKGLERR;
  40.310 +	glUseProgram(prog);
  40.311 +	ShaderProg::current = (ShaderProg*)this;
  40.312 +
  40.313 +	setup_state_uniforms();
  40.314 +}
  40.315 +
  40.316 +
  40.317 +int ShaderProg::get_attrib_location(const char *name) const
  40.318 +{
  40.319 +	glUseProgram(prog);
  40.320 +	return glGetAttribLocation(prog, name);
  40.321 +}
  40.322 +
  40.323 +void ShaderProg::set_attrib_location(const char *name, int loc) const
  40.324 +{
  40.325 +	glBindAttribLocation(prog, loc, name);
  40.326 +	must_link = true;
  40.327 +}
  40.328 +
  40.329 +int ShaderProg::get_uniform_location(const char *name) const
  40.330 +{
  40.331 +	glUseProgram(prog);
  40.332 +	return glGetUniformLocation(prog, name);
  40.333 +}
  40.334 +
  40.335 +bool ShaderProg::set_uniform(int loc, int val) const
  40.336 +{
  40.337 +	glUseProgram(prog);
  40.338 +	if(loc >= 0) {
  40.339 +		glUniform1i(loc, val);
  40.340 +		return true;
  40.341 +	}
  40.342 +	return false;
  40.343 +}
  40.344 +
  40.345 +bool ShaderProg::set_uniform(int loc, float val) const
  40.346 +{
  40.347 +	glUseProgram(prog);
  40.348 +	if(loc >= 0) {
  40.349 +		glUniform1f(loc, val);
  40.350 +		return true;
  40.351 +	}
  40.352 +	return false;
  40.353 +}
  40.354 +
  40.355 +bool ShaderProg::set_uniform(int loc, const Vector2 &v) const
  40.356 +{
  40.357 +	glUseProgram(prog);
  40.358 +	if(loc >= 0) {
  40.359 +		glUniform2f(loc, v.x, v.y);
  40.360 +		return true;
  40.361 +	}
  40.362 +	return false;
  40.363 +}
  40.364 +
  40.365 +bool ShaderProg::set_uniform(int loc, const Vector3 &v) const
  40.366 +{
  40.367 +	glUseProgram(prog);
  40.368 +	if(loc >= 0) {
  40.369 +		glUniform3f(loc, v.x, v.y, v.z);
  40.370 +		return true;
  40.371 +	}
  40.372 +	return false;
  40.373 +}
  40.374 +
  40.375 +bool ShaderProg::set_uniform(int loc, const Vector4 &v) const
  40.376 +{
  40.377 +	glUseProgram(prog);
  40.378 +	if(loc >= 0) {
  40.379 +		glUniform4f(loc, v.x, v.y, v.z, v.w);
  40.380 +		return true;
  40.381 +	}
  40.382 +	return false;
  40.383 +}
  40.384 +
  40.385 +bool ShaderProg::set_uniform(int loc, const Matrix3x3 &m) const
  40.386 +{
  40.387 +	glUseProgram(prog);
  40.388 +	if(loc >= 0) {
  40.389 +		glUniformMatrix3fv(loc, 1, GL_TRUE, m[0]);
  40.390 +		return true;
  40.391 +	}
  40.392 +	return false;
  40.393 +}
  40.394 +
  40.395 +bool ShaderProg::set_uniform(int loc, const Matrix4x4 &m) const
  40.396 +{
  40.397 +	glUseProgram(prog);
  40.398 +	if(loc >= 0) {
  40.399 +		glUniformMatrix4fv(loc, 1, GL_TRUE, m[0]);
  40.400 +		return true;
  40.401 +	}
  40.402 +	return false;
  40.403 +}
  40.404 +
  40.405 +
  40.406 +bool ShaderProg::set_uniform(const char *name, int val) const
  40.407 +{
  40.408 +	return set_uniform(get_uniform_location(name), val);
  40.409 +}
  40.410 +
  40.411 +bool ShaderProg::set_uniform(const char *name, float val) const
  40.412 +{
  40.413 +	return set_uniform(get_uniform_location(name), val);
  40.414 +}
  40.415 +
  40.416 +bool ShaderProg::set_uniform(const char *name, const Vector2 &v) const
  40.417 +{
  40.418 +	return set_uniform(get_uniform_location(name), v);
  40.419 +}
  40.420 +
  40.421 +bool ShaderProg::set_uniform(const char *name, const Vector3 &v) const
  40.422 +{
  40.423 +	return set_uniform(get_uniform_location(name), v);
  40.424 +}
  40.425 +
  40.426 +bool ShaderProg::set_uniform(const char *name, const Vector4 &v) const
  40.427 +{
  40.428 +	return set_uniform(get_uniform_location(name), v);
  40.429 +}
  40.430 +
  40.431 +bool ShaderProg::set_uniform(const char *name, const Matrix3x3 &m) const
  40.432 +{
  40.433 +	return set_uniform(get_uniform_location(name), m);
  40.434 +}
  40.435 +
  40.436 +bool ShaderProg::set_uniform(const char *name, const Matrix4x4 &m) const
  40.437 +{
  40.438 +	return set_uniform(get_uniform_location(name), m);
  40.439 +}
  40.440 +
  40.441 +static StType unist_type(GLenum type)
  40.442 +{
  40.443 +	switch(type) {
  40.444 +	case GL_FLOAT:
  40.445 +		return ST_FLOAT;
  40.446 +	case GL_FLOAT_VEC2:
  40.447 +		return ST_FLOAT2;
  40.448 +	case GL_FLOAT_VEC3:
  40.449 +		return ST_FLOAT3;
  40.450 +	case GL_FLOAT_VEC4:
  40.451 +		return ST_FLOAT4;
  40.452 +	case GL_INT:
  40.453 +	case GL_SAMPLER_2D:
  40.454 +	case GL_SAMPLER_CUBE:
  40.455 +#if !GL_ES_VERSION_2_0
  40.456 +	case GL_SAMPLER_1D:
  40.457 +	case GL_SAMPLER_3D:
  40.458 +	case GL_SAMPLER_1D_SHADOW:
  40.459 +	case GL_SAMPLER_2D_SHADOW:
  40.460 +#endif
  40.461 +		return ST_INT;
  40.462 +	case GL_INT_VEC2:
  40.463 +		return ST_INT2;
  40.464 +	case GL_INT_VEC3:
  40.465 +		return ST_INT3;
  40.466 +	case GL_INT_VEC4:
  40.467 +		return ST_INT4;
  40.468 +	case GL_FLOAT_MAT3:
  40.469 +		return ST_MATRIX3;
  40.470 +	case GL_FLOAT_MAT4:
  40.471 +		return ST_MATRIX4;
  40.472 +	default:
  40.473 +		break;
  40.474 +	}
  40.475 +	return ST_UNKNOWN;
  40.476 +}
  40.477 +
  40.478 +void ShaderProg::cache_state_uniforms() const
  40.479 +{
  40.480 +	if(!glIsProgram(prog)) {
  40.481 +		return;
  40.482 +	}
  40.483 +
  40.484 +	int num_uni;
  40.485 +	glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uni);
  40.486 +
  40.487 +	char name[256];
  40.488 +	for(int i=0; i<num_uni; i++) {
  40.489 +		GLint sz;
  40.490 +		GLenum type;
  40.491 +		glGetActiveUniform(prog, i, sizeof name - 1, 0, &sz, &type, name);
  40.492 +
  40.493 +		if(strstr(name, "st_") == name) {
  40.494 +			StateLocCache s;
  40.495 +			s.sidx = add_unistate(name, unist_type(type));
  40.496 +			s.loc = glGetUniformLocation(prog, name);
  40.497 +			stloc_cache.push_back(s);
  40.498 +		}
  40.499 +	}
  40.500 +}
  40.501 +
  40.502 +void ShaderProg::setup_state_uniforms() const
  40.503 +{
  40.504 +	for(size_t i=0; i<stloc_cache.size(); i++) {
  40.505 +		setup_unistate(stloc_cache[i].sidx, this, stloc_cache[i].loc);
  40.506 +		CHECKGLERR;
  40.507 +	}
  40.508 +}
  40.509 +
  40.510 +// ---- ShaderSet ----
  40.511 +static Shader *load_shader(const char *fname, unsigned int type)
  40.512 +{
  40.513 +	Shader *sdr = new Shader;
  40.514 +	if(!sdr->load(fname, type)) {
  40.515 +		delete sdr;
  40.516 +		return 0;
  40.517 +	}
  40.518 +	return sdr;
  40.519 +}
  40.520 +
  40.521 +static Shader *load_vertex_shader(const char *fname)
  40.522 +{
  40.523 +	return load_shader(fname, GL_VERTEX_SHADER);
  40.524 +}
  40.525 +
  40.526 +static Shader *load_pixel_shader(const char *fname)
  40.527 +{
  40.528 +	return load_shader(fname, GL_FRAGMENT_SHADER);
  40.529 +}
  40.530 +
  40.531 +#ifdef HAVE_GEOMETRY_SHADER
  40.532 +static Shader *load_geom_shader(const char *fname)
  40.533 +{
  40.534 +	return load_shader(fname, GL_GEOMETRY_SHADER);
  40.535 +}
  40.536 +#endif
  40.537 +
  40.538 +#ifdef HAVE_TESSELATION_SHADER
  40.539 +static Shader *load_tc_shader(const char *fname)
  40.540 +{
  40.541 +	return load_shader(fname, GL_TESS_CONTROL_SHADER);
  40.542 +}
  40.543 +
  40.544 +static Shader *load_te_shader(const char *fname)
  40.545 +{
  40.546 +	return load_shader(fname, GL_TESS_EVALUATION_SHADER);
  40.547 +}
  40.548 +#endif
  40.549 +
  40.550 +static void destroy_shader(Shader *sdr)
  40.551 +{
  40.552 +	delete sdr;
  40.553 +}
  40.554 +
  40.555 +ShaderSet::ShaderSet(unsigned int type)
  40.556 +	: DataSet<Shader*>(0, destroy_shader)
  40.557 +{
  40.558 +	this->type = type;
  40.559 +
  40.560 +	switch(type) {
  40.561 +	case GL_VERTEX_SHADER:
  40.562 +		load = load_vertex_shader;
  40.563 +		break;
  40.564 +
  40.565 +	case GL_FRAGMENT_SHADER:
  40.566 +		load = load_pixel_shader;
  40.567 +		break;
  40.568 +
  40.569 +#ifdef HAVE_GEOMETRY_SHADER
  40.570 +	case GL_GEOMETRY_SHADER:
  40.571 +		load = load_geom_shader;
  40.572 +		break;
  40.573 +#endif
  40.574 +
  40.575 +#ifdef HAVE_TESSELATION_SHADER
  40.576 +	case GL_TESS_CONTROL_SHADER:
  40.577 +		load = load_tc_shader;
  40.578 +		break;
  40.579 +
  40.580 +	case GL_TESS_EVALUATION_SHADER:
  40.581 +		load = load_te_shader;
  40.582 +		break;
  40.583 +#endif
  40.584 +
  40.585 +	default:
  40.586 +		error_log("ShaderSet constructed with invalid shader type!\n");
  40.587 +	}
  40.588 +}
  40.589 +
  40.590 +static struct { const char *name; int loc; } attr_loc[] = {
  40.591 +	{"attr_vertex", MESH_ATTR_VERTEX},
  40.592 +	{"attr_normal", MESH_ATTR_NORMAL},
  40.593 +	{"attr_tangent", MESH_ATTR_TANGENT},
  40.594 +	{"attr_texcoord", MESH_ATTR_TEXCOORD},
  40.595 +	{"attr_color", MESH_ATTR_COLOR},
  40.596 +	{"attr_boneweights", MESH_ATTR_BONEWEIGHTS},
  40.597 +	{"attr_boneidx", MESH_ATTR_BONEIDX}
  40.598 +};
  40.599 +
  40.600 +static void bind_standard_attr(const ShaderProg *prog)
  40.601 +{
  40.602 +	// we must link once to find out which are the active attributes
  40.603 +	glLinkProgram(prog->get_id());
  40.604 +
  40.605 +	int num_attr;
  40.606 +	glGetProgramiv(prog->get_id(), GL_ACTIVE_ATTRIBUTES, &num_attr);
  40.607 +
  40.608 +	char name[256];
  40.609 +	for(int i=0; i<num_attr; i++) {
  40.610 +		GLint sz;
  40.611 +		GLenum type;
  40.612 +		glGetActiveAttrib(prog->get_id(), i, sizeof name - 1, 0, &sz, &type, name);
  40.613 +
  40.614 +		for(int j=0; j<sizeof attr_loc / sizeof *attr_loc; j++) {
  40.615 +			if(strcmp(name, attr_loc[j].name) == 0) {
  40.616 +				prog->set_attrib_location(name, attr_loc[j].loc);
  40.617 +			}
  40.618 +		}
  40.619 +	}
  40.620 +}
  40.621 +
  40.622 +
  40.623 +static const char *strtype(unsigned int type)
  40.624 +{
  40.625 +	switch(type) {
  40.626 +	case GL_VERTEX_SHADER:
  40.627 +		return "vertex";
  40.628 +	case GL_FRAGMENT_SHADER:
  40.629 +		return "fragment";
  40.630 +#ifdef HAVE_GEOMETRY_SHADER
  40.631 +	case GL_GEOMETRY_SHADER:
  40.632 +		return "geometry";
  40.633 +#endif
  40.634 +#ifdef HAVE_TESSELATION_SHADER
  40.635 +	case GL_TESS_CONTROL_SHADER:
  40.636 +		return "tesselation control";
  40.637 +	case GL_TESS_EVALUATION_SHADER:
  40.638 +		return "tesselation evaluation";
  40.639 +#endif
  40.640 +	default:
  40.641 +		break;
  40.642 +	}
  40.643 +	return "<unknown>";
  40.644 +}
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/src/shader.h	Thu Nov 14 05:27:09 2013 +0200
    41.3 @@ -0,0 +1,135 @@
    41.4 +#ifndef SHADER_H_
    41.5 +#define SHADER_H_
    41.6 +
    41.7 +#include <vector>
    41.8 +#include "vmath/vmath.h"
    41.9 +#include "opengl.h"
   41.10 +#include "dataset.h"
   41.11 +
   41.12 +class Shader {
   41.13 +private:
   41.14 +	unsigned int sdr;
   41.15 +	unsigned int type;
   41.16 +	char *name;
   41.17 +
   41.18 +public:
   41.19 +	Shader();
   41.20 +	~Shader();
   41.21 +
   41.22 +	unsigned int get_id() const;
   41.23 +
   41.24 +	void set_name(const char *name);
   41.25 +	const char *get_name() const;
   41.26 +
   41.27 +	bool create(const char *src, unsigned int type);
   41.28 +	void destroy();
   41.29 +
   41.30 +	bool load(const char *fname, unsigned int type);
   41.31 +};
   41.32 +
   41.33 +#define VSDR(s)		s, GL_VERTEX_SHADER
   41.34 +#define FSDR(s)		s, GL_FRAGMENT_SHADER
   41.35 +#define PSDR(s)		FSDR(s)
   41.36 +#define GSDR(s)		s, GL_GEOMETRY_SHADER
   41.37 +#define TCSDR(s)	s, GL_TESS_CONTROL_SHADER
   41.38 +#define TESDR(s)	s, GL_TESS_EVALUATION_SHADER
   41.39 +
   41.40 +class ShaderProg {
   41.41 +private:
   41.42 +	unsigned int prog;
   41.43 +	mutable bool must_link;
   41.44 +	std::vector<Shader*> shaders;
   41.45 +
   41.46 +	struct StateLocCache { int sidx, loc; };
   41.47 +	/** a cache of all st_ prefixed uniform locations and their corresponding
   41.48 +	 * index in the global uniform state vector (see unistate.h)
   41.49 +	 */
   41.50 +	mutable std::vector<StateLocCache> stloc_cache;
   41.51 +
   41.52 +	void cache_state_uniforms() const;
   41.53 +	void setup_state_uniforms() const;
   41.54 +
   41.55 +public:
   41.56 +	static ShaderProg *current;
   41.57 +
   41.58 +	ShaderProg();
   41.59 +	~ShaderProg();
   41.60 +
   41.61 +	/// returns the OpenGL object id for this shader program
   41.62 +	unsigned int get_id() const;
   41.63 +
   41.64 +	/** takes a series of shaders, and constructs a program object by linking
   41.65 +	 * them together. Terminate with a null pointer (don't use 0!) */
   41.66 +	bool create(Shader *sdr, ...);
   41.67 +	/// same as above, but with a va_list instead of variable arguments.
   41.68 +	bool create(Shader *sdr, va_list ap);
   41.69 +	/** takes two shaders (vertex and pixel) and constructs a program object by
   41.70 +	 * linking them together. Either one can be null. */
   41.71 +	bool create(Shader *vsdr, Shader *psdr);
   41.72 +
   41.73 +	/** takes a series of shader source/shader type pairs and constructs a program
   41.74 +	 * object by linking them together. Terminate with a null pointer (don't use 0!)
   41.75 +	 * You can use the VSDR, PSDR, GSDR, TCSDR, TESDR convenience macros for passing
   41.76 +	 * the pairs.
   41.77 +	 * Example: create(VSDR(vsrc0), VSDR(vsrc1), PSDR(psrc), NULL);
   41.78 +	 */
   41.79 +	bool create(const char *src, unsigned int type, ...);
   41.80 +	/// same as above, but with a va_list instead of variable arguments.
   41.81 +	bool create(const char *src, unsigned int type, va_list ap);
   41.82 +	/** takes two shaders source strings (vertex and pixel) and constructs
   41.83 +	 * a program object by linking them together. Either one can be null. */
   41.84 +	bool create(const char *vsrc, const char *psrc);
   41.85 +
   41.86 +	void destroy();
   41.87 +
   41.88 +	/** takes a series of shader filename/shader type pairs, loads the shaders and
   41.89 +	 * constructs a program object by linking them together. Terminate with a null
   41.90 +	 * pointer (don't use 0!). You can use the VSDR, PSDR, GSDR, TCSDR, TESDR convenience
   41.91 +	 * macros for passing the pairs.
   41.92 +	 * Example: load(VSDR("vsdr1.glsl"), VSDR("vsdr2.glsl"), PSDR("pixel.glsl"), NULL);
   41.93 +	 */
   41.94 +	bool load(const char *fname, unsigned int type, ...);
   41.95 +	/// same as above, but with a va_list instead of variable arguments.
   41.96 +	bool load(const char *fname, unsigned int type, va_list ap);
   41.97 +	/** takes the filenames of two shader files (vertex and pixel), loads them and
   41.98 +	 * constructs a program object by linking them together. Either one can be null */
   41.99 +	bool load(const char *vsrc, const char *psrc);
  41.100 +
  41.101 +	void add_shader(Shader *sdr);
  41.102 +	bool link() const;
  41.103 +
  41.104 +	void bind() const;
  41.105 +
  41.106 +	int get_attrib_location(const char *name) const;
  41.107 +	void set_attrib_location(const char *name, int loc) const;
  41.108 +
  41.109 +	int get_uniform_location(const char *name) const;
  41.110 +
  41.111 +	bool set_uniform(int loc, int val) const;
  41.112 +	bool set_uniform(int loc, float val) const;
  41.113 +	bool set_uniform(int loc, const Vector2 &v) const;
  41.114 +	bool set_uniform(int loc, const Vector3 &v) const;
  41.115 +	bool set_uniform(int loc, const Vector4 &v) const;
  41.116 +	bool set_uniform(int loc, const Matrix3x3 &m) const;
  41.117 +	bool set_uniform(int loc, const Matrix4x4 &m) const;
  41.118 +
  41.119 +	bool set_uniform(const char *name, int val) const;
  41.120 +	bool set_uniform(const char *name, float val) const;
  41.121 +	bool set_uniform(const char *name, const Vector2 &v) const;
  41.122 +	bool set_uniform(const char *name, const Vector3 &v) const;
  41.123 +	bool set_uniform(const char *name, const Vector4 &v) const;
  41.124 +	bool set_uniform(const char *name, const Matrix3x3 &m) const;
  41.125 +	bool set_uniform(const char *name, const Matrix4x4 &m) const;
  41.126 +
  41.127 +	friend void setup_unistate(const ShaderProg*);
  41.128 +};
  41.129 +
  41.130 +class ShaderSet : public DataSet<Shader*> {
  41.131 +private:
  41.132 +	unsigned int type;
  41.133 +
  41.134 +public:
  41.135 +	ShaderSet(unsigned int type);
  41.136 +};
  41.137 +
  41.138 +#endif	// SHADER_H_
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/src/texgen.cc	Thu Nov 14 05:27:09 2013 +0200
    42.3 @@ -0,0 +1,137 @@
    42.4 +#include "texgen.h"
    42.5 +
    42.6 +static void intcolor(const Vector4 &color, int *icol);
    42.7 +
    42.8 +Image *texgen_solid(int xsz, int ysz, const Vector4 &color)
    42.9 +{
   42.10 +	Image *img = new Image;
   42.11 +	if(!img->create(xsz, ysz, Image::FMT_RGBA)) {
   42.12 +		delete img;
   42.13 +		return 0;
   42.14 +	}
   42.15 +
   42.16 +	int col[4];
   42.17 +	intcolor(color, col);
   42.18 +
   42.19 +	unsigned char *pix = (unsigned char*)img->get_pixels();
   42.20 +	for(int i=0; i<xsz * ysz; i++) {
   42.21 +		*pix++ = col[0];
   42.22 +		*pix++ = col[1];
   42.23 +		*pix++ = col[2];
   42.24 +		*pix++ = col[3];
   42.25 +	}
   42.26 +	return img;
   42.27 +}
   42.28 +
   42.29 +Image *texgen_chess(int xsz, int ysz, int usub, int vsub, const Vector4 &col1, const Vector4 &col2)
   42.30 +{
   42.31 +	Image *img = new Image;
   42.32 +	if(!img->create(xsz, ysz, Image::FMT_RGBA)) {
   42.33 +		delete img;
   42.34 +		return 0;
   42.35 +	}
   42.36 +
   42.37 +	int c1[4], c2[4];
   42.38 +	intcolor(col1, c1);
   42.39 +	intcolor(col2, c2);
   42.40 +
   42.41 +	int udiv = xsz / usub;
   42.42 +	int vdiv = ysz / vsub;
   42.43 +
   42.44 +	unsigned char *pix = (unsigned char*)img->get_pixels();
   42.45 +	for(int i=0; i<ysz; i++) {
   42.46 +		for(int j=0; j<xsz; j++) {
   42.47 +			if(((i / vdiv) & 1) == ((j / udiv) & 1)) {
   42.48 +				*pix++ = c1[0];
   42.49 +				*pix++ = c1[1];
   42.50 +				*pix++ = c1[2];
   42.51 +				*pix++ = c1[3];
   42.52 +			} else {
   42.53 +				*pix++ = c2[0];
   42.54 +				*pix++ = c2[1];
   42.55 +				*pix++ = c2[2];
   42.56 +				*pix++ = c2[3];
   42.57 +			}
   42.58 +		}
   42.59 +	}
   42.60 +	return img;
   42.61 +}
   42.62 +
   42.63 +
   42.64 +Image *texgen(int xsz, int ysz, float usize, float vsize, Vector4 (*eval)(float, float, void*), void *cls)
   42.65 +{
   42.66 +	Image *img = new Image;
   42.67 +	if(!img->create(xsz, ysz, Image::FMT_RGBA)) {
   42.68 +		delete img;
   42.69 +		return 0;
   42.70 +	}
   42.71 +
   42.72 +	unsigned char *pix = (unsigned char*)img->get_pixels();
   42.73 +	for(int i=0; i<ysz; i++) {
   42.74 +		for(int j=0; j<xsz; j++) {
   42.75 +			float x = usize * (float)j / (float)xsz;
   42.76 +			float y = vsize * (float)i / (float)ysz;
   42.77 +
   42.78 +			Vector4 color = eval(x, y, cls);
   42.79 +
   42.80 +			int icol[4];
   42.81 +			intcolor(color, icol);
   42.82 +
   42.83 +			*pix++ = icol[0];
   42.84 +			*pix++ = icol[1];
   42.85 +			*pix++ = icol[2];
   42.86 +			*pix++ = icol[3];
   42.87 +		}
   42.88 +	}
   42.89 +	return img;
   42.90 +}
   42.91 +
   42.92 +
   42.93 +struct NoiseArg {
   42.94 +	int octaves;
   42.95 +	Vector4 col1, col2;
   42.96 +};
   42.97 +
   42.98 +static Vector4 fbm_eval(float x, float y, void *cls)
   42.99 +{
  42.100 +	NoiseArg *arg = (NoiseArg*)cls;
  42.101 +
  42.102 +	float noise = fbm2(x, y, arg->octaves) * 0.5 + 0.5;
  42.103 +	return lerp(arg->col1, arg->col2, noise);
  42.104 +}
  42.105 +
  42.106 +static Vector4 fbm_abs_eval(float x, float y, void *cls)
  42.107 +{
  42.108 +	NoiseArg *arg = (NoiseArg*)cls;
  42.109 +
  42.110 +	float noise = turbulence2(x, y, arg->octaves) * 0.5 + 0.5;
  42.111 +	return lerp(arg->col1, arg->col2, noise);
  42.112 +}
  42.113 +
  42.114 +
  42.115 +Image *texgen_fbm(int xsz, int ysz, float usize, float vsize, int octaves, const Vector4 &col1, const Vector4 &col2)
  42.116 +{
  42.117 +	NoiseArg arg = {octaves, col1, col2};
  42.118 +	if(arg.octaves < 1) {
  42.119 +		arg.octaves = 1;
  42.120 +	}
  42.121 +
  42.122 +	return texgen(xsz, ysz, usize, vsize, fbm_eval, &arg);
  42.123 +}
  42.124 +
  42.125 +Image *texgen_fbm_abs(int xsz, int ysz, float usize, float vsize, int octaves, const Vector4 &col1, const Vector4 &col2)
  42.126 +{
  42.127 +	NoiseArg arg = {octaves, col1, col2};
  42.128 +	if(arg.octaves < 1) {
  42.129 +		arg.octaves = 1;
  42.130 +	}
  42.131 +
  42.132 +	return texgen(xsz, ysz, usize, vsize, fbm_abs_eval, &arg);
  42.133 +}
  42.134 +
  42.135 +static inline void intcolor(const Vector4 &color, int *icol)
  42.136 +{
  42.137 +	for(int i=0; i<4; i++) {
  42.138 +		icol[i] = std::max(std::min((int)(color[i] * 255.0), 255), 0);
  42.139 +	}
  42.140 +}
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/src/texgen.h	Thu Nov 14 05:27:09 2013 +0200
    43.3 @@ -0,0 +1,14 @@
    43.4 +#ifndef TEXGEN_H_
    43.5 +#define TEXGEN_H_
    43.6 +
    43.7 +#include "image.h"
    43.8 +#include "vmath/vmath.h"
    43.9 +
   43.10 +Image *texgen_solid(int xsz, int ysz, const Vector4 &color);
   43.11 +Image *texgen_chess(int xsz, int ysz, int usub, int vsub, const Vector4 &col1, const Vector4 &col2);
   43.12 +Image *texgen_fbm(int xsz, int ysz, float usize, float vsize, int octaves, const Vector4 &col1, const Vector4 &col2);
   43.13 +Image *texgen_fbm_abs(int xsz, int ysz, float usize, float vsize, int octaves, const Vector4 &col1, const Vector4 &col2);
   43.14 +
   43.15 +Image *texgen(int xsz, int ysz, float usize, float vsize, Vector4 (*eval)(float, float, void*), void *cls);
   43.16 +
   43.17 +#endif	// TEXGEN_H_
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/src/texman.cc	Thu Nov 14 05:27:09 2013 +0200
    44.3 @@ -0,0 +1,3 @@
    44.4 +#include "texman.h"
    44.5 +
    44.6 +TextureSet texset;
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/src/texman.h	Thu Nov 14 05:27:09 2013 +0200
    45.3 @@ -0,0 +1,8 @@
    45.4 +#ifndef TEXMAN_H_
    45.5 +#define TEXMAN_H_
    45.6 +
    45.7 +#include "texture.h"
    45.8 +
    45.9 +extern TextureSet texset;
   45.10 +
   45.11 +#endif	// TEXMAN_H_
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/src/texture.cc	Thu Nov 14 05:27:09 2013 +0200
    46.3 @@ -0,0 +1,370 @@
    46.4 +#include "texture.h"
    46.5 +#include "image.h"
    46.6 +#include "opengl.h"
    46.7 +#include "imago2.h"
    46.8 +#include "logger.h"
    46.9 +#include "datapath.h"
   46.10 +
   46.11 +static int glifmt_from_ifmt(unsigned int ifmt);
   46.12 +static int glfmt_from_ifmt(unsigned int ifmt);
   46.13 +static int gltype_from_ifmt(unsigned int ifmt);
   46.14 +
   46.15 +static int glifmt_from_imgfmt(Image::Format fmt);
   46.16 +
   46.17 +static unsigned int cur_target[8] = {
   46.18 +	GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D,
   46.19 +	GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D
   46.20 +};
   46.21 +
   46.22 +void set_texture(Texture *tex, int tunit)
   46.23 +{
   46.24 +	if(tex) {
   46.25 +		tex->bind(tunit);
   46.26 +	} else {
   46.27 +		glActiveTexture(GL_TEXTURE0 + tunit);
   46.28 +		glBindTexture(cur_target[tunit], 0);
   46.29 +		glActiveTexture(GL_TEXTURE0);
   46.30 +	}
   46.31 +}
   46.32 +
   46.33 +Texture *load_texture(const char *fname)
   46.34 +{
   46.35 +	TextureCube *texcube = new TextureCube;
   46.36 +	if(texcube->load(fname)) {
   46.37 +		return texcube;
   46.38 +	}
   46.39 +	delete texcube;
   46.40 +
   46.41 +	Texture2D *tex = new Texture2D;
   46.42 +	if(tex->load(fname)) {
   46.43 +		return tex;
   46.44 +	}
   46.45 +	delete tex;
   46.46 +	return 0;
   46.47 +}
   46.48 +
   46.49 +
   46.50 +Texture::Texture()
   46.51 +{
   46.52 +	target = 0;
   46.53 +	sz[0] = sz[1] = sz[2] = 0;
   46.54 +	texfmt = 0;
   46.55 +
   46.56 +	glGenTextures(1, &id);
   46.57 +}
   46.58 +
   46.59 +Texture::~Texture()
   46.60 +{
   46.61 +	if(id) {
   46.62 +		glDeleteTextures(1, &id);
   46.63 +	}
   46.64 +}
   46.65 +
   46.66 +void Texture::set_wrapping(unsigned int wrap)
   46.67 +{
   46.68 +	if(!target) {
   46.69 +		return;
   46.70 +	}
   46.71 +
   46.72 +	glBindTexture(target, id);
   46.73 +	glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
   46.74 +	glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
   46.75 +}
   46.76 +
   46.77 +void Texture::set_filtering(unsigned int filt)
   46.78 +{
   46.79 +	unsigned int mag_filter;
   46.80 +
   46.81 +	if(!target) {
   46.82 +		return;
   46.83 +	}
   46.84 +
   46.85 +	switch(filt) {
   46.86 +	case GL_LINEAR_MIPMAP_NEAREST:
   46.87 +	case GL_LINEAR_MIPMAP_LINEAR:
   46.88 +		mag_filter = GL_LINEAR;
   46.89 +		break;
   46.90 +
   46.91 +	case GL_NEAREST_MIPMAP_NEAREST:
   46.92 +	case GL_NEAREST_MIPMAP_LINEAR:
   46.93 +		mag_filter = GL_NEAREST;
   46.94 +		break;
   46.95 +
   46.96 +	default:
   46.97 +		mag_filter = filt;
   46.98 +	}
   46.99 +
  46.100 +	set_filtering(filt, mag_filter);
  46.101 +}
  46.102 +
  46.103 +void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt)
  46.104 +{
  46.105 +	glBindTexture(target, id);
  46.106 +	glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt);
  46.107 +	glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt);
  46.108 +}
  46.109 +
  46.110 +unsigned int Texture::get_format() const
  46.111 +{
  46.112 +	return texfmt;
  46.113 +}
  46.114 +
  46.115 +int Texture::get_size(int dim) const
  46.116 +{
  46.117 +	if(dim < 0 || dim >= 3) {
  46.118 +		return 0;
  46.119 +	}
  46.120 +	return sz[dim];
  46.121 +}
  46.122 +
  46.123 +unsigned int Texture::get_id() const
  46.124 +{
  46.125 +	return id;
  46.126 +}
  46.127 +
  46.128 +void Texture::bind(int tex_unit) const
  46.129 +{
  46.130 +	glActiveTexture(GL_TEXTURE0 + tex_unit);
  46.131 +	glBindTexture(target, id);
  46.132 +	glActiveTexture(GL_TEXTURE0);
  46.133 +
  46.134 +	cur_target[tex_unit] = target;
  46.135 +}
  46.136 +
  46.137 +
  46.138 +// ---- Texture2D ----
  46.139 +
  46.140 +Texture2D::Texture2D()
  46.141 +{
  46.142 +	target = GL_TEXTURE_2D;
  46.143 +}
  46.144 +
  46.145 +void Texture2D::create(int xsz, int ysz, unsigned int ifmt)
  46.146 +{
  46.147 +	int fmt = glfmt_from_ifmt(ifmt);
  46.148 +	int type = gltype_from_ifmt(ifmt);
  46.149 +
  46.150 +	glBindTexture(GL_TEXTURE_2D, id);
  46.151 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  46.152 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  46.153 +	glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0);
  46.154 +	CHECKGLERR;
  46.155 +	sz[0] = xsz;
  46.156 +	sz[1] = ysz;
  46.157 +	texfmt = ifmt;
  46.158 +}
  46.159 +
  46.160 +void Texture2D::set_image(const Image &img, int idx)
  46.161 +{
  46.162 +	texfmt = glifmt_from_imgfmt(img.get_format());
  46.163 +	unsigned int fmt = glfmt_from_ifmt(texfmt);
  46.164 +	unsigned int type = gltype_from_ifmt(texfmt);
  46.165 +
  46.166 +	sz[0] = img.get_width();
  46.167 +	sz[1] = img.get_height();
  46.168 +
  46.169 +	glBindTexture(GL_TEXTURE_2D, id);
  46.170 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  46.171 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  46.172 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  46.173 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  46.174 +
  46.175 +#ifdef __GLEW_H__
  46.176 +	if(GLEW_SGIS_generate_mipmap) {
  46.177 +		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
  46.178 +#endif
  46.179 +		glTexImage2D(GL_TEXTURE_2D, 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
  46.180 +#ifdef __GLEW_H__
  46.181 +	} else {
  46.182 +		gluBuild2DMipmaps(GL_TEXTURE_2D, texfmt, sz[0], sz[1], fmt, type, img.get_pixels());
  46.183 +	}
  46.184 +#endif
  46.185 +
  46.186 +#ifdef GL_ES_VERSION_2_0
  46.187 +	glGenerateMipmap(GL_TEXTURE_2D);
  46.188 +#endif
  46.189 +}
  46.190 +
  46.191 +bool Texture2D::load(const char *fname)
  46.192 +{
  46.193 +	Image img;
  46.194 +	if(!img.load(fname) == -1) {
  46.195 +		error_log("failed to load 2D texture: %s\n", fname);
  46.196 +		return false;
  46.197 +	}
  46.198 +	set_image(img);
  46.199 +
  46.200 +	info_log("loaded 2D texture: %s\n", fname);
  46.201 +	return true;
  46.202 +}
  46.203 +
  46.204 +bool Texture2D::save(const char *fname) const
  46.205 +{
  46.206 +#ifndef GL_ES_VERSION_2_0
  46.207 +	unsigned char *pixels = new unsigned char[sz[0] * sz[1] * 4];
  46.208 +
  46.209 +	glBindTexture(GL_TEXTURE_2D, id);
  46.210 +	glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  46.211 +
  46.212 +	if(img_save_pixels(fname, pixels, sz[0], sz[1]) == -1) {
  46.213 +		error_log("failed to save 2D texture: %s\n", fname);
  46.214 +		delete [] pixels;
  46.215 +		return false;
  46.216 +	}
  46.217 +
  46.218 +	info_log("saved 2D texture: %s\n", fname);
  46.219 +	delete [] pixels;
  46.220 +	return true;
  46.221 +#else
  46.222 +	return false;	// TODO
  46.223 +#endif
  46.224 +}
  46.225 +
  46.226 +// ---- TextureCube ----
  46.227 +static unsigned int cube_faces[] = {
  46.228 +	GL_TEXTURE_CUBE_MAP_POSITIVE_X,
  46.229 +	GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
  46.230 +	GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
  46.231 +	GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
  46.232 +	GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
  46.233 +	GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
  46.234 +};
  46.235 +
  46.236 +TextureCube::TextureCube()
  46.237 +{
  46.238 +	target = GL_TEXTURE_CUBE_MAP;
  46.239 +}
  46.240 +
  46.241 +void TextureCube::create(int xsz, int ysz, unsigned int ifmt)
  46.242 +{
  46.243 +	if(xsz != ysz) {
  46.244 +		error_log("trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz);
  46.245 +		return;
  46.246 +	}
  46.247 +
  46.248 +	texfmt = ifmt;
  46.249 +
  46.250 +	glBindTexture(GL_TEXTURE_CUBE_MAP, id);
  46.251 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  46.252 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  46.253 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  46.254 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  46.255 +
  46.256 +	for(int i=0; i<6; i++) {
  46.257 +		glTexImage2D(cube_faces[i], 0, ifmt, xsz, ysz, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
  46.258 +	}
  46.259 +}
  46.260 +
  46.261 +void TextureCube::set_image(const Image &img, int idx)
  46.262 +{
  46.263 +	// TODO
  46.264 +}
  46.265 +
  46.266 +bool TextureCube::load(const char *fname)
  46.267 +{
  46.268 +	return false;	// TODO
  46.269 +}
  46.270 +
  46.271 +bool TextureCube::save(const char *fname) const
  46.272 +{
  46.273 +	return false;	// TODO
  46.274 +}
  46.275 +
  46.276 +static int glifmt_from_ifmt(unsigned int ifmt)
  46.277 +{
  46.278 +#ifdef GL_ES_VERSION_2_0
  46.279 +	switch(ifmt) {
  46.280 +	case GL_LUMINANCE16F:
  46.281 +	case GL_LUMINANCE32F:
  46.282 +		ifmt = GL_LUMINANCE;
  46.283 +		break;
  46.284 +
  46.285 +	case GL_RGB16F:
  46.286 +	case GL_RGB32F:
  46.287 +		ifmt = GL_RGB;
  46.288 +		break;
  46.289 +
  46.290 +	case GL_RGBA16F:
  46.291 +	case GL_RGBA32F:
  46.292 +		ifmt = GL_RGBA;
  46.293 +		break;
  46.294 +
  46.295 +	default:
  46.296 +		break;
  46.297 +	}
  46.298 +#endif
  46.299 +	return ifmt;	// by default just pass it through...
  46.300 +}
  46.301 +
  46.302 +static int glfmt_from_ifmt(unsigned int ifmt)
  46.303 +{
  46.304 +	switch(ifmt) {
  46.305 +	case GL_LUMINANCE16F:
  46.306 +	case GL_LUMINANCE32F:
  46.307 +		return GL_LUMINANCE;
  46.308 +
  46.309 +	case GL_RGB16F:
  46.310 +	case GL_RGB32F:
  46.311 +		return GL_RGB;
  46.312 +
  46.313 +	case GL_RGBA16F:
  46.314 +	case GL_RGBA32F:
  46.315 +		return GL_RGBA;
  46.316 +
  46.317 +	default:
  46.318 +		break;
  46.319 +	}
  46.320 +	return ifmt;
  46.321 +}
  46.322 +
  46.323 +static int gltype_from_ifmt(unsigned int ifmt)
  46.324 +{
  46.325 +	switch(ifmt) {
  46.326 +	case GL_RGB16F:
  46.327 +	case GL_RGBA16F:
  46.328 +	case GL_LUMINANCE16F:
  46.329 +#ifdef GL_ES_VERSION_2_0
  46.330 +		return GL_HALF_FLOAT_OES;
  46.331 +#endif
  46.332 +	case GL_RGB32F:
  46.333 +	case GL_RGBA32F:
  46.334 +	case GL_LUMINANCE32F:
  46.335 +		return GL_FLOAT;
  46.336 +
  46.337 +	default:
  46.338 +		break;
  46.339 +	}
  46.340 +	return GL_UNSIGNED_BYTE;
  46.341 +}
  46.342 +
  46.343 +static int glifmt_from_imgfmt(Image::Format fmt)
  46.344 +{
  46.345 +	switch(fmt) {
  46.346 +	case Image::FMT_GREY:
  46.347 +		return GL_LUMINANCE;
  46.348 +	case Image::FMT_GREY_FLOAT:
  46.349 +		return GL_LUMINANCE16F;
  46.350 +	case Image::FMT_RGB:
  46.351 +		return GL_RGB;
  46.352 +	case Image::FMT_RGB_FLOAT:
  46.353 +		return GL_RGB16F;
  46.354 +	case Image::FMT_RGBA:
  46.355 +		return GL_RGBA;
  46.356 +	case Image::FMT_RGBA_FLOAT:
  46.357 +		return GL_RGBA16F;
  46.358 +	default:
  46.359 +		break;
  46.360 +	}
  46.361 +	return 0;
  46.362 +}
  46.363 +
  46.364 +// ---- TextureSet ----
  46.365 +static void destroy_texture(Texture *tex)
  46.366 +{
  46.367 +	delete tex;
  46.368 +}
  46.369 +
  46.370 +TextureSet::TextureSet()
  46.371 +	: DataSet<Texture*>(load_texture, destroy_texture)
  46.372 +{
  46.373 +}
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/src/texture.h	Thu Nov 14 05:27:09 2013 +0200
    47.3 @@ -0,0 +1,76 @@
    47.4 +#ifndef TEXTURE_H_
    47.5 +#define TEXTURE_H_
    47.6 +
    47.7 +#include "dataset.h"
    47.8 +#include "opengl.h"
    47.9 +
   47.10 +class Image;
   47.11 +
   47.12 +class Texture {
   47.13 +protected:
   47.14 +	unsigned int id;
   47.15 +	unsigned int target;
   47.16 +	unsigned int texfmt;
   47.17 +	int sz[3];
   47.18 +
   47.19 +	Texture(const Texture &tex) {}
   47.20 +	Texture &operator =(const Texture &tex) { return *this; }
   47.21 +
   47.22 +public:
   47.23 +	Texture();
   47.24 +	virtual ~Texture();
   47.25 +
   47.26 +	void set_wrapping(unsigned int wrap);
   47.27 +	void set_filtering(unsigned int filt);
   47.28 +	void set_filtering(unsigned int min_filt, unsigned int mag_filt);
   47.29 +
   47.30 +	unsigned int get_format() const;
   47.31 +
   47.32 +	virtual int get_size(int dim) const;
   47.33 +
   47.34 +	virtual void create(int xsz, int ysz, unsigned int ifmt = GL_RGBA) = 0;
   47.35 +	virtual void set_image(const Image &img, int idx = 0) = 0;
   47.36 +
   47.37 +	virtual bool load(const char *fname) = 0;
   47.38 +	virtual bool save(const char *fname) const = 0;
   47.39 +
   47.40 +	virtual unsigned int get_id() const;
   47.41 +
   47.42 +	virtual void bind(int tex_unit = 0) const;
   47.43 +};
   47.44 +
   47.45 +class Texture2D : public Texture {
   47.46 +public:
   47.47 +	Texture2D();
   47.48 +
   47.49 +	virtual void create(int xsz, int ysz, unsigned int ifmt = GL_RGBA);
   47.50 +	virtual void set_image(const Image &img, int idx = 0);
   47.51 +
   47.52 +	virtual bool load(const char *fname);
   47.53 +	virtual bool save(const char *fname) const;
   47.54 +};
   47.55 +
   47.56 +class TextureCube : public Texture {
   47.57 +public:
   47.58 +	TextureCube();
   47.59 +
   47.60 +	virtual void create(int xsz, int ysz, unsigned int ifmt = GL_RGBA);
   47.61 +	virtual void set_image(const Image &img, int idx = 0);
   47.62 +
   47.63 +	virtual bool load(const char *fname);
   47.64 +	virtual bool save(const char *fname) const;
   47.65 +};
   47.66 +
   47.67 +void set_texture(Texture *tex, int tunit = 0);
   47.68 +
   47.69 +/** loads a texture autodetecting whether it's a 2D texture or
   47.70 + * cubemap and creating the correct Texture subclass instance.
   47.71 + */
   47.72 +Texture *load_texture(const char *fname);
   47.73 +
   47.74 +class TextureSet : public DataSet<Texture*> {
   47.75 +public:
   47.76 +	TextureSet();
   47.77 +};
   47.78 +
   47.79 +#endif	// TEXTURE_H_
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/src/timer.cc	Thu Nov 14 05:27:09 2013 +0200
    48.3 @@ -0,0 +1,118 @@
    48.4 +#include "timer.h"
    48.5 +
    48.6 +#if defined(__APPLE__) && !defined(__unix__)
    48.7 +#define __unix__
    48.8 +#endif
    48.9 +
   48.10 +#ifdef __unix__
   48.11 +#include <time.h>
   48.12 +#include <unistd.h>
   48.13 +#include <sys/time.h>
   48.14 +
   48.15 +#ifdef CLOCK_MONOTONIC
   48.16 +unsigned long get_time_msec(void)
   48.17 +{
   48.18 +	struct timespec ts;
   48.19 +	static struct timespec ts0;
   48.20 +
   48.21 +	clock_gettime(CLOCK_MONOTONIC, &ts);
   48.22 +	if(ts0.tv_sec == 0 && ts0.tv_nsec == 0) {
   48.23 +		ts0 = ts;
   48.24 +		return 0;
   48.25 +	}
   48.26 +	return (ts.tv_sec - ts0.tv_sec) * 1000 + (ts.tv_nsec - ts0.tv_nsec) / 1000000;
   48.27 +}
   48.28 +#else	/* no fancy POSIX clocks, fallback to good'ol gettimeofday */
   48.29 +unsigned long get_time_msec(void)
   48.30 +{
   48.31 +	struct timeval tv;
   48.32 +	static struct timeval tv0;
   48.33 +
   48.34 +	gettimeofday(&tv, 0);
   48.35 +	if(tv0.tv_sec == 0 && tv0.tv_usec == 0) {
   48.36 +		tv0 = tv;
   48.37 +		return 0;
   48.38 +	}
   48.39 +	return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000;
   48.40 +}
   48.41 +#endif	/* !posix clock */
   48.42 +
   48.43 +void sleep_msec(unsigned long msec)
   48.44 +{
   48.45 +	usleep(msec * 1000);
   48.46 +}
   48.47 +#endif
   48.48 +
   48.49 +#ifdef WIN32
   48.50 +#include <windows.h>
   48.51 +#pragma comment(lib, "winmm.lib")
   48.52 +
   48.53 +unsigned long get_time_msec(void)
   48.54 +{
   48.55 +	return timeGetTime();
   48.56 +}
   48.57 +
   48.58 +void sleep_msec(unsigned long msec)
   48.59 +{
   48.60 +	Sleep(msec);
   48.61 +}
   48.62 +#endif
   48.63 +
   48.64 +double get_time_sec(void)
   48.65 +{
   48.66 +	return get_time_msec() / 1000.0f;
   48.67 +}
   48.68 +
   48.69 +void sleep_sec(double sec)
   48.70 +{
   48.71 +	if(sec > 0.0f) {
   48.72 +		sleep_msec(sec * 1000.0f);
   48.73 +	}
   48.74 +}
   48.75 +
   48.76 +
   48.77 +Timer::Timer()
   48.78 +{
   48.79 +	reset();
   48.80 +}
   48.81 +
   48.82 +void Timer::reset()
   48.83 +{
   48.84 +	pause_time = 0;
   48.85 +	start_time = get_time_msec();
   48.86 +}
   48.87 +
   48.88 +void Timer::start()
   48.89 +{
   48.90 +	if(!is_running()) {
   48.91 +		// resuming
   48.92 +		start_time += get_time_msec() - pause_time;
   48.93 +		pause_time = 0;
   48.94 +	}
   48.95 +}
   48.96 +
   48.97 +void Timer::stop()
   48.98 +{
   48.99 +	if(is_running()) {
  48.100 +		pause_time = get_time_msec();
  48.101 +	}
  48.102 +}
  48.103 +
  48.104 +bool Timer::is_running() const
  48.105 +{
  48.106 +	return pause_time == 0;
  48.107 +}
  48.108 +
  48.109 +unsigned long Timer::get_msec() const
  48.110 +{
  48.111 +	if(!is_running()) {
  48.112 +		// in paused state...
  48.113 +		return pause_time - start_time;
  48.114 +	}
  48.115 +	return get_time_msec() - start_time;
  48.116 +}
  48.117 +
  48.118 +double Timer::get_sec() const
  48.119 +{
  48.120 +	return (double)get_msec() / 1000.0;
  48.121 +}
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/src/timer.h	Thu Nov 14 05:27:09 2013 +0200
    49.3 @@ -0,0 +1,29 @@
    49.4 +#ifndef TIMER_H_
    49.5 +#define TIMER_H_
    49.6 +
    49.7 +unsigned long get_time_msec(void);
    49.8 +void sleep_msec(unsigned long msec);
    49.9 +
   49.10 +double get_time_sec(void);
   49.11 +void sleep_sec(double sec);
   49.12 +
   49.13 +
   49.14 +class Timer {
   49.15 +private:
   49.16 +	unsigned long start_time, pause_time;
   49.17 +
   49.18 +public:
   49.19 +	Timer();
   49.20 +
   49.21 +	void reset();
   49.22 +
   49.23 +	void start();
   49.24 +	void stop();
   49.25 +
   49.26 +	bool is_running() const;
   49.27 +
   49.28 +	unsigned long get_msec() const;
   49.29 +	double get_sec() const;
   49.30 +};
   49.31 +
   49.32 +#endif	// TIMER_H_
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/src/unistate.cc	Thu Nov 14 05:27:09 2013 +0200
    50.3 @@ -0,0 +1,678 @@
    50.4 +#include <map>
    50.5 +#include <vector>
    50.6 +#include "unistate.h"
    50.7 +#include "shader.h"
    50.8 +#include "logger.h"
    50.9 +
   50.10 +struct StateItem {
   50.11 +	StType type;
   50.12 +
   50.13 +	union {
   50.14 +		int ival[4];
   50.15 +		float fval[16];
   50.16 +	};
   50.17 +	int transpose;	// for matrices
   50.18 +};
   50.19 +
   50.20 +static const char *typestr(StType type);
   50.21 +static int type_nelem(StType type);
   50.22 +static StType float_type(int elem);
   50.23 +static StType int_type(int elem);
   50.24 +
   50.25 +std::vector<StateItem> state;
   50.26 +std::map<std::string, int> stateidx;
   50.27 +
   50.28 +
   50.29 +int add_unistate(const char *name, StType type)
   50.30 +{
   50.31 +	static const float ident3[] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
   50.32 +	static const float ident4[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
   50.33 +
   50.34 +	if(stateidx.find(name) != stateidx.end()) {
   50.35 +		return stateidx[name];
   50.36 +	}
   50.37 +
   50.38 +	StateItem sitem;
   50.39 +	memset(&sitem, 0, sizeof sitem);
   50.40 +	sitem.type = type;
   50.41 +
   50.42 +	// initialize to a reasonable default value
   50.43 +	switch(type) {
   50.44 +	case ST_MATRIX3:
   50.45 +		memcpy(sitem.fval, ident3, sizeof ident3);
   50.46 +		break;
   50.47 +
   50.48 +	case ST_MATRIX4:
   50.49 +		memcpy(sitem.fval, ident4, sizeof ident4);
   50.50 +		break;
   50.51 +
   50.52 +	default:
   50.53 +		break;	// in all other cases leave it zero (see memset above)
   50.54 +	}
   50.55 +
   50.56 +	int sidx = state.size();
   50.57 +	state.push_back(sitem);
   50.58 +	stateidx[name] = sidx;
   50.59 +
   50.60 +	debug_log("adding uniform state [%d]: %s %s\n", sidx, typestr(sitem.type), name);
   50.61 +
   50.62 +	return sidx;
   50.63 +}
   50.64 +
   50.65 +int get_unistate_index(const char *name)
   50.66 +{
   50.67 +	std::map<std::string, int>::const_iterator it = stateidx.find(name);
   50.68 +	if(it != stateidx.end()) {
   50.69 +		return it->second;
   50.70 +	}
   50.71 +	return -1;
   50.72 +}
   50.73 +
   50.74 +#define CHECK_INDEX(i)	\
   50.75 +	if(i < 0 || i >= (int)state.size()) return
   50.76 +
   50.77 +#define CHECK_COUNT(count, type) \
   50.78 +	do { \
   50.79 +		int max_elem = type_nelem(type); \
   50.80 +		if(!(count) || (count) > max_elem) { \
   50.81 +			count = max_elem; \
   50.82 +		} \
   50.83 +	} while(0)
   50.84 +
   50.85 +void set_unistate(int sidx, const int *val, int count)
   50.86 +{
   50.87 +	CHECK_INDEX(sidx);
   50.88 +	CHECK_COUNT(count, state[sidx].type);
   50.89 +
   50.90 +	memcpy(state[sidx].ival, val, count * sizeof *state[sidx].ival);
   50.91 +}
   50.92 +
   50.93 +void set_unistate(int sidx, const float *val, int count)
   50.94 +{
   50.95 +	CHECK_INDEX(sidx);
   50.96 +	CHECK_COUNT(count, state[sidx].type);
   50.97 +
   50.98 +	memcpy(state[sidx].fval, val, count * sizeof *state[sidx].fval);
   50.99 +	state[sidx].transpose = 0;
  50.100 +}
  50.101 +
  50.102 +void get_unistate(int sidx, int *val, int count)
  50.103 +{
  50.104 +	CHECK_INDEX(sidx);
  50.105 +	CHECK_COUNT(count, state[sidx].type);
  50.106 +
  50.107 +	memcpy(val, state[sidx].ival, count * sizeof *val);
  50.108 +}
  50.109 +
  50.110 +void get_unistate(int sidx, float *val, int count)
  50.111 +{
  50.112 +	CHECK_INDEX(sidx);
  50.113 +	CHECK_COUNT(count, state[sidx].type);
  50.114 +
  50.115 +	memcpy(val, state[sidx].fval, count * sizeof *val);
  50.116 +}
  50.117 +
  50.118 +void set_unistate(int sidx, int val)
  50.119 +{
  50.120 +	set_unistate(sidx, &val, 1);
  50.121 +}
  50.122 +
  50.123 +void set_unistate(int sidx, float val)
  50.124 +{
  50.125 +	set_unistate(sidx, &val, 1);
  50.126 +}
  50.127 +
  50.128 +void set_unistate(int sidx, const Vector2 &vec)
  50.129 +{
  50.130 +	set_unistate(sidx, &vec.x, 2);
  50.131 +}
  50.132 +
  50.133 +void set_unistate(int sidx, const Vector3 &vec)
  50.134 +{
  50.135 +	set_unistate(sidx, &vec.x, 3);
  50.136 +}
  50.137 +
  50.138 +void set_unistate(int sidx, const Vector4 &vec)
  50.139 +{
  50.140 +	set_unistate(sidx, &vec.x, 4);
  50.141 +}
  50.142 +
  50.143 +void set_unistate(int sidx, const Matrix3x3 &mat)
  50.144 +{
  50.145 +	set_unistate(sidx, mat[0], 9);
  50.146 +	state[sidx].transpose = 1;
  50.147 +}
  50.148 +
  50.149 +void set_unistate(int sidx, const Matrix4x4 &mat)
  50.150 +{
  50.151 +	set_unistate(sidx, mat[0], 16);
  50.152 +	state[sidx].transpose = 1;
  50.153 +}
  50.154 +
  50.155 +
  50.156 +int set_unistate(const char *name, int *val, int count)
  50.157 +{
  50.158 +	int sidx = get_unistate_index(name);
  50.159 +	if(sidx < 0) {
  50.160 +		StType type = int_type(count);
  50.161 +		if(type == ST_UNKNOWN) {
  50.162 +			error_log("invalid element count (%d) while setting previously unknown unistate item \"%s\"\n",
  50.163 +					count, name);
  50.164 +			return -1;
  50.165 +		}
  50.166 +
  50.167 +		sidx = add_unistate(name, type);
  50.168 +	}
  50.169 +	set_unistate(sidx, val);
  50.170 +	return sidx;
  50.171 +}
  50.172 +
  50.173 +int set_unistate(const char *name, float *val, int count)
  50.174 +{
  50.175 +	int sidx = get_unistate_index(name);
  50.176 +	if(sidx < 0) {
  50.177 +		StType type = float_type(count);
  50.178 +		if(type == ST_UNKNOWN) {
  50.179 +			error_log("invalid element count (%d) while setting previously unknown unistate item \"%s\"\n",
  50.180 +					count, name);
  50.181 +			return -1;
  50.182 +		}
  50.183 +
  50.184 +		sidx = add_unistate(name, type);
  50.185 +	}
  50.186 +	set_unistate(sidx, val);
  50.187 +	return sidx;
  50.188 +}
  50.189 +
  50.190 +int set_unistate(const char *name, int val)
  50.191 +{
  50.192 +	int sidx = get_unistate_index(name);
  50.193 +	if(sidx < 0) {
  50.194 +		sidx = add_unistate(name, ST_INT);
  50.195 +	}
  50.196 +	set_unistate(sidx, val);
  50.197 +	return sidx;
  50.198 +}
  50.199 +
  50.200 +int set_unistate(const char *name, float val)
  50.201 +{
  50.202 +	int sidx = get_unistate_index(name);
  50.203 +	if(sidx < 0) {
  50.204 +		sidx = add_unistate(name, ST_FLOAT);
  50.205 +	}
  50.206 +	set_unistate(sidx, val);
  50.207 +	return sidx;
  50.208 +}
  50.209 +
  50.210 +int set_unistate(const char *name, const Vector2 &vec)
  50.211 +{
  50.212 +	int sidx = get_unistate_index(name);
  50.213 +	if(sidx < 0) {
  50.214 +		sidx = add_unistate(name, ST_FLOAT2);
  50.215 +	}
  50.216 +	set_unistate(sidx, vec);
  50.217 +	return sidx;
  50.218 +}
  50.219 +
  50.220 +int set_unistate(const char *name, const Vector3 &vec)
  50.221 +{
  50.222 +	int sidx = get_unistate_index(name);
  50.223 +	if(sidx < 0) {
  50.224 +		sidx = add_unistate(name, ST_FLOAT3);
  50.225 +	}
  50.226 +	set_unistate(sidx, vec);
  50.227 +	return sidx;
  50.228 +}
  50.229 +
  50.230 +int set_unistate(const char *name, const Vector4 &vec)
  50.231 +{
  50.232 +	int sidx = get_unistate_index(name);
  50.233 +	if(sidx < 0) {
  50.234 +		sidx = add_unistate(name, ST_FLOAT4);
  50.235 +	}
  50.236 +	set_unistate(sidx, vec);
  50.237 +	return sidx;
  50.238 +}
  50.239 +
  50.240 +int set_unistate(const char *name, const Matrix3x3 &mat)
  50.241 +{
  50.242 +	int sidx = get_unistate_index(name);
  50.243 +	if(sidx < 0) {
  50.244 +		sidx = add_unistate(name, ST_MATRIX3);
  50.245 +	}
  50.246 +	set_unistate(sidx, mat);
  50.247 +	return sidx;
  50.248 +}
  50.249 +
  50.250 +int set_unistate(const char *name, const Matrix4x4 &mat)
  50.251 +{
  50.252 +	int sidx = get_unistate_index(name);
  50.253 +	if(sidx < 0) {
  50.254 +		sidx = add_unistate(name, ST_MATRIX4);
  50.255 +	}
  50.256 +	set_unistate(sidx, mat);
  50.257 +	return sidx;
  50.258 +}
  50.259 +
  50.260 +
  50.261 +int get_unistate_int(int sidx)
  50.262 +{
  50.263 +	int val = 0;
  50.264 +	get_unistate(sidx, &val, 1);
  50.265 +	return val;
  50.266 +}
  50.267 +
  50.268 +float get_unistate_float(int sidx)
  50.269 +{
  50.270 +	float val = 0.0f;
  50.271 +	get_unistate(sidx, &val, 1);
  50.272 +	return val;
  50.273 +}
  50.274 +
  50.275 +Vector2 get_unistate_vec2(int sidx)
  50.276 +{
  50.277 +	float val[2] = {0.0f, 0.0f};
  50.278 +	get_unistate(sidx, val, 2);
  50.279 +	return Vector2(val[0], val[1]);
  50.280 +}
  50.281 +
  50.282 +Vector3 get_unistate_vec3(int sidx)
  50.283 +{
  50.284 +	float val[3] = {0.0f, 0.0f, 0.0f};
  50.285 +	get_unistate(sidx, val, 3);
  50.286 +	return Vector3(val[0], val[1], val[2]);
  50.287 +}
  50.288 +
  50.289 +Vector4 get_unistate_vec4(int sidx)
  50.290 +{
  50.291 +	float val[4] = {0.0f, 0.0f, 0.0f};
  50.292 +	get_unistate(sidx, val, 4);
  50.293 +	return Vector4(val[0], val[1], val[2], val[3]);
  50.294 +}
  50.295 +
  50.296 +Matrix3x3 get_unistate_mat3(int sidx)
  50.297 +{
  50.298 +	Matrix3x3 res;
  50.299 +	get_unistate(sidx, res.m[0], 9);
  50.300 +	return res;
  50.301 +}
  50.302 +
  50.303 +Matrix4x4 get_unistate_mat4(int sidx)
  50.304 +{
  50.305 +	Matrix4x4 res;
  50.306 +	get_unistate(sidx, res.m[0], 16);
  50.307 +	return res;
  50.308 +}
  50.309 +
  50.310 +
  50.311 +int get_unistate_int(const char *name)
  50.312 +{
  50.313 +	int sidx = get_unistate_index(name);
  50.314 +	if(sidx == -1) {
  50.315 +		return 0;
  50.316 +	}
  50.317 +	return get_unistate_int(sidx);
  50.318 +}
  50.319 +
  50.320 +float get_unistate_float(const char *name)
  50.321 +{
  50.322 +	int sidx = get_unistate_index(name);
  50.323 +	if(sidx == -1) {
  50.324 +		return 0.0f;
  50.325 +	}
  50.326 +	return get_unistate_float(sidx);
  50.327 +}
  50.328 +
  50.329 +Vector2 get_unistate_vec2(const char *name)
  50.330 +{
  50.331 +	int sidx = get_unistate_index(name);
  50.332 +	if(sidx == -1) {
  50.333 +		return Vector2();
  50.334 +	}
  50.335 +	return get_unistate_vec2(sidx);
  50.336 +}
  50.337 +
  50.338 +Vector3 get_unistate_vec3(const char *name)
  50.339 +{
  50.340 +	int sidx = get_unistate_index(name);
  50.341 +	if(sidx == -1) {
  50.342 +		return Vector3();
  50.343 +	}
  50.344 +	return get_unistate_vec3(sidx);
  50.345 +}
  50.346 +
  50.347 +Vector4 get_unistate_vec4(const char *name)
  50.348 +{
  50.349 +	int sidx = get_unistate_index(name);
  50.350 +	if(sidx == -1) {
  50.351 +		return Vector4();
  50.352 +	}
  50.353 +	return get_unistate_vec4(sidx);
  50.354 +}
  50.355 +
  50.356 +Matrix3x3 get_unistate_mat3(const char *name)
  50.357 +{
  50.358 +	int sidx = get_unistate_index(name);
  50.359 +	if(sidx == -1) {
  50.360 +		return Matrix3x3();
  50.361 +	}
  50.362 +	return get_unistate_mat3(sidx);
  50.363 +}
  50.364 +
  50.365 +Matrix4x4 get_unistate_mat4(const char *name)
  50.366 +{
  50.367 +	int sidx = get_unistate_index(name);
  50.368 +	if(sidx == -1) {
  50.369 +		return Matrix4x4();
  50.370 +	}
  50.371 +	return get_unistate_mat4(sidx);
  50.372 +}
  50.373 +
  50.374 +
  50.375 +void setup_unistate(const ShaderProg *sdr)
  50.376 +{
  50.377 +	if(!sdr) {
  50.378 +		if(!(sdr = ShaderProg::current)) {
  50.379 +			return;
  50.380 +		}
  50.381 +	}
  50.382 +
  50.383 +	sdr->setup_state_uniforms();
  50.384 +}
  50.385 +
  50.386 +bool setup_unistate(int sidx, const ShaderProg *sdr, int loc)
  50.387 +{
  50.388 +	if(loc < 0 || sidx < 0 || sidx >= (int)state.size()) {
  50.389 +		return false;
  50.390 +	}
  50.391 +
  50.392 +	CHECKGLERR;
  50.393 +	glUseProgram(sdr->get_id());
  50.394 +	CHECKGLERR;
  50.395 +
  50.396 +	switch(state[sidx].type) {
  50.397 +	case ST_INT:
  50.398 +		glUniform1iv(loc, 1, state[sidx].ival);
  50.399 +		break;
  50.400 +	case ST_INT2:
  50.401 +		glUniform2iv(loc, 1, state[sidx].ival);
  50.402 +		break;
  50.403 +	case ST_INT3:
  50.404 +		glUniform3iv(loc, 1, state[sidx].ival);
  50.405 +		break;
  50.406 +	case ST_INT4:
  50.407 +		glUniform4iv(loc, 1, state[sidx].ival);
  50.408 +		break;
  50.409 +
  50.410 +	case ST_FLOAT:
  50.411 +		glUniform1fv(loc, 1, state[sidx].fval);
  50.412 +		break;
  50.413 +	case ST_FLOAT2:
  50.414 +		glUniform2fv(loc, 1, state[sidx].fval);
  50.415 +		break;
  50.416 +	case ST_FLOAT3:
  50.417 +		glUniform3fv(loc, 1, state[sidx].fval);
  50.418 +		break;
  50.419 +	case ST_FLOAT4:
  50.420 +		glUniform4fv(loc, 1, state[sidx].fval);
  50.421 +		break;
  50.422 +
  50.423 +	case ST_MATRIX3:
  50.424 +#ifdef GL_ES_VERSION_2_0
  50.425 +		{
  50.426 +			float tmat[9], *ptr = tmat;
  50.427 +			for(int i=0; i<3; i++) {
  50.428 +				for(int j=0; j<3; j++) {
  50.429 +					*ptr++ = state[sidx].fval[j * 3 + i];
  50.430 +				}
  50.431 +			}
  50.432 +			glUniformMatrix3fv(loc, 1, GL_FALSE, tmat);
  50.433 +		}
  50.434 +#else
  50.435 +		glUniformMatrix3fv(loc, 1, state[sidx].transpose, state[sidx].fval);
  50.436 +#endif
  50.437 +		break;
  50.438 +
  50.439 +	case ST_MATRIX4:
  50.440 +#ifdef GL_ES_VERSION_2_0
  50.441 +		{
  50.442 +			float tmat[16], *ptr = tmat;
  50.443 +			for(int i=0; i<4; i++) {
  50.444 +				for(int j=0; j<4; j++) {
  50.445 +					*ptr++ = state[sidx].fval[j * 4 + i];
  50.446 +				}
  50.447 +			}
  50.448 +			glUniformMatrix4fv(loc, 1, GL_FALSE, tmat);
  50.449 +		}
  50.450 +#else
  50.451 +		glUniformMatrix4fv(loc, 1, state[sidx].transpose, state[sidx].fval);
  50.452 +#endif
  50.453 +		break;
  50.454 +
  50.455 +	default:
  50.456 +		return false;
  50.457 +	}
  50.458 +
  50.459 +	CHECKGLERR;
  50.460 +	return true;
  50.461 +}
  50.462 +
  50.463 +bool setup_unistate(const char *name, const ShaderProg *sdr)
  50.464 +{
  50.465 +	int loc = sdr->get_uniform_location(name);
  50.466 +	if(loc == -1) {
  50.467 +		return false;
  50.468 +	}
  50.469 +	return setup_unistate(get_unistate_index(name), sdr, loc);
  50.470 +}
  50.471 +
  50.472 +void set_world_matrix(const Matrix4x4 &mat)
  50.473 +{
  50.474 +	static int sidx = -1, sidx_transp, sidx_mat3;
  50.475 +
  50.476 +	if(sidx == -1) {
  50.477 +		sidx = add_unistate("st_world_matrix", ST_MATRIX4);
  50.478 +		sidx_mat3 = add_unistate("st_world_matrix3", ST_MATRIX3);
  50.479 +		sidx_transp = add_unistate("st_world_matrix_transpose", ST_MATRIX4);
  50.480 +	}
  50.481 +
  50.482 +	set_unistate(sidx, mat);
  50.483 +	set_unistate(sidx_mat3, Matrix3x3(mat));
  50.484 +	set_unistate(sidx_transp, mat[0]);	// by using the float* variant, we unset the transpose flag
  50.485 +}
  50.486 +
  50.487 +void set_view_matrix(const Matrix4x4 &mat)
  50.488 +{
  50.489 +	static int sidx = -1, sidx_transp, sidx_mat3;
  50.490 +
  50.491 +	if(sidx == -1) {
  50.492 +		sidx = add_unistate("st_view_matrix", ST_MATRIX4);
  50.493 +		sidx_mat3 = add_unistate("st_view_matrix3", ST_MATRIX3);
  50.494 +		sidx_transp = add_unistate("st_view_matrix_transpose", ST_MATRIX4);
  50.495 +	}
  50.496 +
  50.497 +	set_unistate(sidx, mat);
  50.498 +	set_unistate(sidx_mat3, Matrix3x3(mat));
  50.499 +	set_unistate(sidx_transp, mat[0]);	// by using the float* variant, we unset the transpose flag
  50.500 +}
  50.501 +
  50.502 +void set_projection_matrix(const Matrix4x4 &mat)
  50.503 +{
  50.504 +	static int sidx = -1;
  50.505 +
  50.506 +	if(sidx == -1) {
  50.507 +		sidx = add_unistate("st_proj_matrix", ST_MATRIX4);
  50.508 +	}
  50.509 +
  50.510 +	set_unistate(sidx, mat);
  50.511 +}
  50.512 +
  50.513 +void set_texture_matrix(const Matrix4x4 &mat)
  50.514 +{
  50.515 +	static int sidx = -1;
  50.516 +
  50.517 +	if(sidx == -1) {
  50.518 +		sidx = add_unistate("st_tex_matrix", ST_MATRIX4);
  50.519 +	}
  50.520 +
  50.521 +	set_unistate(sidx, mat);
  50.522 +}
  50.523 +
  50.524 +Matrix4x4 get_world_matrix()
  50.525 +{
  50.526 +	static int sidx = -1;
  50.527 +
  50.528 +	if(sidx == -1) {
  50.529 +		if((sidx = get_unistate_index("st_world_matrix")) == -1) {
  50.530 +			return Matrix4x4();
  50.531 +		}
  50.532 +	}
  50.533 +	return get_unistate_mat4(sidx);
  50.534 +}
  50.535 +
  50.536 +Matrix4x4 get_view_matrix()
  50.537 +{
  50.538 +	static int sidx = -1;
  50.539 +
  50.540 +	if(sidx == -1) {
  50.541 +		if((sidx = get_unistate_index("st_view_matrix")) == -1) {
  50.542 +			return Matrix4x4();
  50.543 +		}
  50.544 +	}
  50.545 +	return get_unistate_mat4(sidx);
  50.546 +}
  50.547 +
  50.548 +Matrix4x4 get_projection_matrix()
  50.549 +{
  50.550 +	static int sidx = -1;
  50.551 +
  50.552 +	if(sidx == -1) {
  50.553 +		if((sidx = get_unistate_index("st_proj_matrix")) == -1) {
  50.554 +			return Matrix4x4();
  50.555 +		}
  50.556 +	}
  50.557 +	return get_unistate_mat4(sidx);
  50.558 +}
  50.559 +
  50.560 +Matrix4x4 get_texture_matrix()
  50.561 +{
  50.562 +	static int sidx = -1;
  50.563 +
  50.564 +	if(sidx == -1) {
  50.565 +		if((sidx = get_unistate_index("st_tex_matrix")) == -1) {
  50.566 +			return Matrix4x4();
  50.567 +		}
  50.568 +	}
  50.569 +	return get_unistate_mat4(sidx);
  50.570 +}
  50.571 +
  50.572 +void setup_gl_matrices()
  50.573 +{
  50.574 +#ifdef USE_OLDGL
  50.575 +	Matrix4x4 modelview = get_world_matrix() * get_view_matrix();
  50.576 +	Matrix4x4 proj = get_projection_matrix();
  50.577 +	Matrix4x4 tex = get_texture_matrix();
  50.578 +
  50.579 +	glMatrixMode(GL_TEXTURE);
  50.580 +	glLoadTransposeMatrixf(tex[0]);
  50.581 +	glMatrixMode(GL_PROJECTION);
  50.582 +	glLoadTransposeMatrixf(proj[0]);
  50.583 +	glMatrixMode(GL_MODELVIEW);
  50.584 +	glLoadTransposeMatrixf(modelview[0]);
  50.585 +#endif
  50.586 +}
  50.587 +
  50.588 +static const char *typestr(StType type)
  50.589 +{
  50.590 +	switch(type) {
  50.591 +	case ST_INT:
  50.592 +		return "int";
  50.593 +	case ST_INT2:
  50.594 +		return "ivec2";
  50.595 +	case ST_INT3:
  50.596 +		return "ivec3";
  50.597 +	case ST_INT4:
  50.598 +		return "ivec4";
  50.599 +	case ST_FLOAT:
  50.600 +		return "float";
  50.601 +	case ST_FLOAT2:
  50.602 +		return "vec2";
  50.603 +	case ST_FLOAT3:
  50.604 +		return "vec3";
  50.605 +	case ST_FLOAT4:
  50.606 +		return "vec4";
  50.607 +	case ST_MATRIX3:
  50.608 +		return "mat3";
  50.609 +	case ST_MATRIX4:
  50.610 +		return "mat4";
  50.611 +
  50.612 +	default:
  50.613 +		break;
  50.614 +	}
  50.615 +	return "<unknown>";
  50.616 +}
  50.617 +
  50.618 +static int type_nelem(StType type)
  50.619 +{
  50.620 +	switch(type) {
  50.621 +	case ST_INT:
  50.622 +	case ST_FLOAT:
  50.623 +		return 1;
  50.624 +	case ST_INT2:
  50.625 +	case ST_FLOAT2:
  50.626 +		return 2;
  50.627 +	case ST_INT3:
  50.628 +	case ST_FLOAT3:
  50.629 +		return 3;
  50.630 +	case ST_INT4:
  50.631 +	case ST_FLOAT4:
  50.632 +		return 4;
  50.633 +	case ST_MATRIX3:
  50.634 +		return 9;
  50.635 +	case ST_MATRIX4:
  50.636 +		return 16;
  50.637 +
  50.638 +	default:
  50.639 +		break;
  50.640 +	}
  50.641 +
  50.642 +	return 0;
  50.643 +}
  50.644 +
  50.645 +static StType float_type(int elem)
  50.646 +{
  50.647 +	switch(elem) {
  50.648 +	case 1:
  50.649 +		return ST_FLOAT;
  50.650 +	case 2:
  50.651 +		return ST_FLOAT2;
  50.652 +	case 3:
  50.653 +		return ST_FLOAT3;
  50.654 +	case 4:
  50.655 +		return ST_FLOAT4;
  50.656 +	case 9:
  50.657 +		return ST_MATRIX3;
  50.658 +	case 16:
  50.659 +		return ST_MATRIX4;
  50.660 +	default:
  50.661 +		break;
  50.662 +	}
  50.663 +	return ST_UNKNOWN;
  50.664 +}
  50.665 +
  50.666 +static StType int_type(int elem)
  50.667 +{
  50.668 +	switch(elem) {
  50.669 +	case 1:
  50.670 +		return ST_INT;
  50.671 +	case 2:
  50.672 +		return ST_INT2;
  50.673 +	case 3:
  50.674 +		return ST_INT3;
  50.675 +	case 4:
  50.676 +		return ST_INT4;
  50.677 +	default:
  50.678 +		break;
  50.679 +	}
  50.680 +	return ST_UNKNOWN;
  50.681 +}
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/src/unistate.h	Thu Nov 14 05:27:09 2013 +0200
    51.3 @@ -0,0 +1,104 @@
    51.4 +#ifndef UNISTATE_H_
    51.5 +#define UNISTATE_H_
    51.6 +
    51.7 +#include "vmath/vmath.h"
    51.8 +
    51.9 +class ShaderProg;
   51.10 +
   51.11 +enum StType {
   51.12 +	ST_UNKNOWN,
   51.13 +	ST_INT,	ST_INT2, ST_INT3, ST_INT4,
   51.14 +	ST_FLOAT, ST_FLOAT2, ST_FLOAT3, ST_FLOAT4,
   51.15 +	ST_MATRIX3, ST_MATRIX4
   51.16 +};
   51.17 +
   51.18 +int add_unistate(const char *name, StType type);
   51.19 +int get_unistate_index(const char *name);
   51.20 +
   51.21 +/** set the uniform state identified by \param sidx by copying
   51.22 + * a number of elements from \param val. If \param count is 0
   51.23 + * then it's automatically set based on the type of this state item.
   51.24 + * @{ */
   51.25 +void set_unistate(int sidx, const int *val, int count = 0);
   51.26 +void set_unistate(int sidx, const float *val, int count = 0);
   51.27 +/// @}
   51.28 +
   51.29 +/** get the uniform state identified by \param sidx by copying
   51.30 + * a number of elements into \param val. If \param count is 0
   51.31 + * then it's automatically set based on the type of this state item.
   51.32 + * @{ */
   51.33 +void get_unistate(int sidx, int *val, int count = 0);
   51.34 +void get_unistate(int sidx, float *val, int count = 0);
   51.35 +/// @}
   51.36 +
   51.37 +/// convenience versions of set_unistate @{
   51.38 +void set_unistate(int sidx, int val);
   51.39 +void set_unistate(int sidx, float val);
   51.40 +void set_unistate(int sidx, const Vector2 &vec);
   51.41 +void set_unistate(int sidx, const Vector3 &vec);
   51.42 +void set_unistate(int sidx, const Vector4 &vec);
   51.43 +void set_unistate(int sidx, const Matrix3x3 &mat);
   51.44 +void set_unistate(int sidx, const Matrix4x4 &mat);
   51.45 +/// @}
   51.46 +
   51.47 +/** convenience functions for setting the uniform state by name.
   51.48 + * if the name cannot be found in the current set of uniform state
   51.49 + * items, a new one is created with a type derived from the variant
   51.50 + * of the function that was called (which might not be what you want).
   51.51 + * The index of the state item is returned.
   51.52 + * @{ */
   51.53 +int set_unistate(const char *name, int *val, int count = 0);
   51.54 +int set_unistate(const char *name, float *val, int count = 0);
   51.55 +int set_unistate(const char *name, int val);
   51.56 +int set_unistate(const char *name, float val);
   51.57 +int set_unistate(const char *name, const Vector2 &vec);
   51.58 +int set_unistate(const char *name, const Vector3 &vec);
   51.59 +int set_unistate(const char *name, const Vector4 &vec);
   51.60 +int set_unistate(const char *name, const Matrix3x3 &mat);
   51.61 +int set_unistate(const char *name, const Matrix4x4 &mat);
   51.62 +/// @}
   51.63 +
   51.64 +/// convenience versions of get_unistate @{
   51.65 +int get_unistate_int(int sidx);
   51.66 +float get_unistate_float(int sidx);
   51.67 +Vector2 get_unistate_vec2(int sidx);
   51.68 +Vector3 get_unistate_vec3(int sidx);
   51.69 +Vector4 get_unistate_vec4(int sidx);
   51.70 +Matrix3x3 get_unistate_mat3(int sidx);
   51.71 +Matrix4x4 get_unistate_mat4(int sidx);
   51.72 +/// @}
   51.73 +
   51.74 +/// convenience versions of get_unistate for getting the uniform state by name @{
   51.75 +int get_unistate_int(const char *name);
   51.76 +float get_unistate_float(const char *name);
   51.77 +Vector2 get_unistate_vec2(const char *name);
   51.78 +Vector3 get_unistate_vec3(const char *name);
   51.79 +Vector4 get_unistate_vec4(const char *name);
   51.80 +Matrix3x3 get_unistate_mat3(const char *name);
   51.81 +Matrix4x4 get_unistate_mat4(const char *name);
   51.82 +/// @}
   51.83 +
   51.84 +/** Prepare for rendering by setting up all the state uniforms in the shader sdr.
   51.85 + * If sdr is null, then use the "current" shader as per ShaderProg::current
   51.86 + */
   51.87 +void setup_unistate(const ShaderProg *sdr = 0);
   51.88 +
   51.89 +bool setup_unistate(int sidx, const ShaderProg *sdr, int loc);
   51.90 +bool setup_unistate(const char *name, const ShaderProg *sdr);
   51.91 +
   51.92 +// special functions for setting the rendering pipeline matrices
   51.93 +void set_world_matrix(const Matrix4x4 &mat);
   51.94 +void set_view_matrix(const Matrix4x4 &mat);
   51.95 +void set_projection_matrix(const Matrix4x4 &mat);
   51.96 +void set_texture_matrix(const Matrix4x4 &mat);
   51.97 +
   51.98 +Matrix4x4 get_world_matrix();
   51.99 +Matrix4x4 get_view_matrix();
  51.100 +Matrix4x4 get_projection_matrix();
  51.101 +Matrix4x4 get_texture_matrix();
  51.102 +
  51.103 +void setup_gl_matrices();	// this shouldn't be needed in the final code
  51.104 +
  51.105 +// TODO should do a matrix stack at some point ...
  51.106 +
  51.107 +#endif	// UNISTATE_H_
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/src/xform_node.cc	Thu Nov 14 05:27:09 2013 +0200
    52.3 @@ -0,0 +1,370 @@
    52.4 +#include <assert.h>
    52.5 +#include <algorithm>
    52.6 +#include "xform_node.h"
    52.7 +#include "anim/anim.h"
    52.8 +#include "anim/track.h"
    52.9 +
   52.10 +static inline anm_interpolator track_interpolator(Interp in);
   52.11 +static inline anm_extrapolator track_extrapolator(Extrap ex);
   52.12 +
   52.13 +XFormNode::XFormNode()
   52.14 +{
   52.15 +	anm = new anm_node;
   52.16 +	anm_init_node(anm);
   52.17 +}
   52.18 +
   52.19 +XFormNode::~XFormNode()
   52.20 +{
   52.21 +	anm_destroy_node(anm);
   52.22 +	delete anm;
   52.23 +}
   52.24 +
   52.25 +void XFormNode::set_name(const char *name)
   52.26 +{
   52.27 +	anm_set_node_name(anm, name);
   52.28 +}
   52.29 +
   52.30 +const char *XFormNode::get_name() const
   52.31 +{
   52.32 +	return anm_get_node_name(anm);
   52.33 +}
   52.34 +
   52.35 +void XFormNode::set_interpolator(Interp in)
   52.36 +{
   52.37 +	anm_set_interpolator(anm, track_interpolator(in));
   52.38 +	interp = in;
   52.39 +}
   52.40 +
   52.41 +Interp XFormNode::get_interpolator() const
   52.42 +{
   52.43 +	return interp;
   52.44 +}
   52.45 +
   52.46 +void XFormNode::set_extrapolator(Extrap ex)
   52.47 +{
   52.48 +	anm_set_extrapolator(anm, track_extrapolator(ex));
   52.49 +	extrap = ex;
   52.50 +}
   52.51 +
   52.52 +Extrap XFormNode::get_extrapolator() const
   52.53 +{
   52.54 +	return extrap;
   52.55 +}
   52.56 +
   52.57 +void XFormNode::add_child(XFormNode *child)
   52.58 +{
   52.59 +	children.push_back(child);
   52.60 +	anm_link_node(anm, child->anm);
   52.61 +}
   52.62 +
   52.63 +void XFormNode::remove_child(XFormNode *child)
   52.64 +{
   52.65 +	std::vector<XFormNode*>::iterator it;
   52.66 +	it = std::find(children.begin(), children.end(), child);
   52.67 +	if(it != children.end()) {
   52.68 +		children.erase(it);
   52.69 +		anm_unlink_node(anm, child->anm);
   52.70 +	}
   52.71 +}
   52.72 +
   52.73 +int XFormNode::get_children_count() const
   52.74 +{
   52.75 +	return (int)children.size();
   52.76 +}
   52.77 +
   52.78 +XFormNode *XFormNode::get_child(int idx)
   52.79 +{
   52.80 +	if(idx >= 0 && idx < get_children_count()) {
   52.81 +		return children[idx];
   52.82 +	}
   52.83 +	return 0;
   52.84 +}
   52.85 +
   52.86 +const XFormNode *XFormNode::get_child(int idx) const
   52.87 +{
   52.88 +	if(idx >= 0 && idx < get_children_count()) {
   52.89 +		return children[idx];
   52.90 +	}
   52.91 +	return 0;
   52.92 +}
   52.93 +
   52.94 +void XFormNode::set_position(const Vector3 &pos, long tmsec)
   52.95 +{
   52.96 +	anm_set_position(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec));
   52.97 +}
   52.98 +
   52.99 +Vector3 XFormNode::get_node_position(long tmsec) const
  52.100 +{
  52.101 +	vec3_t p = anm_get_node_position(anm, ANM_MSEC2TM(tmsec));
  52.102 +	return Vector3(p.x, p.y, p.z);
  52.103 +}
  52.104 +
  52.105 +void XFormNode::set_rotation(const Quaternion &quat, long tmsec)
  52.106 +{
  52.107 +	anm_set_rotation(anm, quat_cons(quat.s, quat.v.x, quat.v.y, quat.v.z), ANM_MSEC2TM(tmsec));
  52.108 +}
  52.109 +
  52.110 +Quaternion XFormNode::get_node_rotation(long tmsec) const
  52.111 +{
  52.112 +	quat_t q = anm_get_node_rotation(anm, ANM_MSEC2TM(tmsec));
  52.113 +	return Quaternion(q.w, q.x, q.y, q.z);
  52.114 +}
  52.115 +
  52.116 +void XFormNode::set_scaling(const Vector3 &pos, long tmsec)
  52.117 +{
  52.118 +	anm_set_scaling(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec));
  52.119 +}
  52.120 +
  52.121 +Vector3 XFormNode::get_node_scaling(long tmsec) const
  52.122 +{
  52.123 +	vec3_t s = anm_get_node_scaling(anm, ANM_MSEC2TM(tmsec));
  52.124 +	return Vector3(s.x, s.y, s.z);
  52.125 +}
  52.126 +
  52.127 +// these take hierarchy into account
  52.128 +Vector3 XFormNode::get_position(long tmsec) const
  52.129 +{
  52.130 +	vec3_t v = anm_get_position(anm, ANM_MSEC2TM(tmsec));
  52.131 +	return Vector3(v.x, v.y, v.z);
  52.132 +}
  52.133 +
  52.134 +Quaternion XFormNode::get_rotation(long tmsec) const
  52.135 +{
  52.136 +	quat_t q = anm_get_rotation(anm, tmsec);
  52.137 +	return Quaternion(q.w, q.x, q.y, q.z);
  52.138 +}
  52.139 +
  52.140 +Vector3 XFormNode::get_scaling(long tmsec) const
  52.141 +{
  52.142 +	vec3_t v = anm_get_scaling(anm, ANM_MSEC2TM(tmsec));
  52.143 +	return Vector3(v.x, v.y, v.z);
  52.144 +}
  52.145 +
  52.146 +void XFormNode::set_pivot(const Vector3 &pivot)
  52.147 +{
  52.148 +	anm_set_pivot(anm, v3_cons(pivot.x, pivot.y, pivot.z));
  52.149 +}
  52.150 +
  52.151 +Vector3 XFormNode::get_pivot() const
  52.152 +{
  52.153 +	vec3_t p = anm_get_pivot(anm);
  52.154 +	return Vector3(p.x, p.y, p.z);
  52.155 +}
  52.156 +
  52.157 +void XFormNode::set_local_matrix(const Matrix4x4 &mat)
  52.158 +{
  52.159 +	local_matrix = mat;
  52.160 +}
  52.161 +
  52.162 +const Matrix4x4 &XFormNode::get_local_matrix() const
  52.163 +{
  52.164 +	return local_matrix;
  52.165 +}
  52.166 +
  52.167 +void XFormNode::set_bone_matrix(const Matrix4x4 &bmat)
  52.168 +{
  52.169 +	bone_matrix = bmat;
  52.170 +}
  52.171 +
  52.172 +const Matrix4x4 &XFormNode::get_bone_matrix() const
  52.173 +{
  52.174 +	return bone_matrix;
  52.175 +}
  52.176 +
  52.177 +#define FOO
  52.178 +
  52.179 +void XFormNode::get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const
  52.180 +{
  52.181 +	anm_time_t tm = ANM_MSEC2TM(tmsec);
  52.182 +
  52.183 +	if(mat) {
  52.184 +		anm_get_node_matrix(anm, (scalar_t(*)[4])mat, tm);
  52.185 +#ifdef FOO
  52.186 +		*mat = local_matrix * *mat;
  52.187 +#else
  52.188 +		*mat = *mat * local_matrix;
  52.189 +#endif
  52.190 +	}
  52.191 +	if(inv_mat) {
  52.192 +		anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm);
  52.193 +	}
  52.194 +}
  52.195 +
  52.196 +void XFormNode::get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const
  52.197 +{
  52.198 +	anm_time_t tm = ANM_MSEC2TM(tmsec);
  52.199 +
  52.200 +	if(mat) {
  52.201 +		anm_get_matrix(anm, (scalar_t(*)[4])mat, tm);
  52.202 +#ifdef FOO
  52.203 +		*mat = local_matrix * *mat;
  52.204 +#else
  52.205 +		*mat = *mat * local_matrix;
  52.206 +#endif
  52.207 +	}
  52.208 +	if(inv_mat) {
  52.209 +		anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm);
  52.210 +	}
  52.211 +}
  52.212 +
  52.213 +
  52.214 +// ---- Track ----
  52.215 +
  52.216 +Track::Track()
  52.217 +{
  52.218 +	trk = new anm_track;
  52.219 +	anm_init_track(trk);
  52.220 +}
  52.221 +
  52.222 +Track::~Track()
  52.223 +{
  52.224 +	anm_destroy_track(trk);
  52.225 +	delete trk;
  52.226 +}
  52.227 +
  52.228 +Track::Track(const Track &rhs)
  52.229 +{
  52.230 +	trk = new anm_track;
  52.231 +	anm_init_track(trk);
  52.232 +	anm_copy_track(trk, rhs.trk);
  52.233 +	interp = rhs.interp;
  52.234 +	extrap = rhs.extrap;
  52.235 +}
  52.236 +
  52.237 +Track &Track::operator =(const Track &rhs)
  52.238 +{
  52.239 +	if(&rhs == this) {
  52.240 +		return *this;
  52.241 +	}
  52.242 +
  52.243 +	anm_copy_track(trk, rhs.trk);
  52.244 +	interp = rhs.interp;
  52.245 +	extrap = rhs.extrap;
  52.246 +	return *this;
  52.247 +}
  52.248 +
  52.249 +
  52.250 +void Track::set_interpolator(Interp in)
  52.251 +{
  52.252 +	anm_set_track_interpolator(trk, track_interpolator(in));
  52.253 +	interp = in;
  52.254 +}
  52.255 +
  52.256 +Interp Track::get_interpolator() const
  52.257 +{
  52.258 +	return interp;
  52.259 +}
  52.260 +
  52.261 +void Track::set_extrapolator(Extrap ex)
  52.262 +{
  52.263 +	anm_set_track_extrapolator(trk, track_extrapolator(ex));
  52.264 +	extrap = ex;
  52.265 +}
  52.266 +
  52.267 +Extrap Track::get_extrapolator() const
  52.268 +{
  52.269 +	return extrap;
  52.270 +}
  52.271 +
  52.272 +void Track::set_default(double def)
  52.273 +{
  52.274 +	anm_set_track_default(trk, def);
  52.275 +}
  52.276 +
  52.277 +void Track::set_value(float val, long tmsec)
  52.278 +{
  52.279 +	anm_set_value(trk, ANM_MSEC2TM(tmsec), val);
  52.280 +}
  52.281 +
  52.282 +float Track::get_value(long tmsec) const
  52.283 +{
  52.284 +	return anm_get_value(trk, ANM_MSEC2TM(tmsec));
  52.285 +}
  52.286 +
  52.287 +float Track::operator ()(long tmsec) const
  52.288 +{
  52.289 +	return anm_get_value(trk, ANM_MSEC2TM(tmsec));
  52.290 +}
  52.291 +
  52.292 +
  52.293 +// ---- Track3 ----
  52.294 +
  52.295 +void Track3::set_interpolator(Interp in)
  52.296 +{
  52.297 +	for(int i=0; i<3; i++) {
  52.298 +		track[i].set_interpolator(in);
  52.299 +	}
  52.300 +}
  52.301 +
  52.302 +Interp Track3::get_interpolator() const
  52.303 +{
  52.304 +	return track[0].get_interpolator();
  52.305 +}
  52.306 +
  52.307 +void Track3::set_extrapolator(Extrap ex)
  52.308 +{
  52.309 +	for(int i=0; i<3; i++) {
  52.310 +		track[i].set_extrapolator(ex);
  52.311 +	}
  52.312 +}
  52.313 +
  52.314 +Extrap Track3::get_extrapolator() const
  52.315 +{
  52.316 +	return track[0].get_extrapolator();
  52.317 +}
  52.318 +
  52.319 +void Track3::set_default(const Vector3 &def)
  52.320 +{
  52.321 +	for(int i=0; i<3; i++) {
  52.322 +		track[i].set_default(def[i]);
  52.323 +	}
  52.324 +}
  52.325 +
  52.326 +void Track3::set_value(const Vector3 &val, long tmsec)
  52.327 +{
  52.328 +	for(int i=0; i<3; i++) {
  52.329 +		track[i].set_value(val[i], tmsec);
  52.330 +	}
  52.331 +}
  52.332 +
  52.333 +Vector3 Track3::get_value(long tmsec) const
  52.334 +{
  52.335 +	return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec));
  52.336 +}
  52.337 +
  52.338 +Vector3 Track3::operator ()(long tmsec) const
  52.339 +{
  52.340 +	return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec));
  52.341 +}
  52.342 +
  52.343 +
  52.344 +static inline anm_interpolator track_interpolator(Interp in)
  52.345 +{
  52.346 +	switch(in) {
  52.347 +	case INTERP_STEP:
  52.348 +		return ANM_INTERP_STEP;
  52.349 +	case INTERP_LINEAR:
  52.350 +		return ANM_INTERP_LINEAR;
  52.351 +	case INTERP_CUBIC:
  52.352 +		return ANM_INTERP_CUBIC;
  52.353 +	}
  52.354 +
  52.355 +	assert(0);
  52.356 +	return ANM_INTERP_STEP;
  52.357 +}
  52.358 +
  52.359 +static inline anm_extrapolator track_extrapolator(Extrap ex)
  52.360 +{
  52.361 +	switch(ex) {
  52.362 +	case EXTRAP_EXTEND:
  52.363 +		return ANM_EXTRAP_EXTEND;
  52.364 +	case EXTRAP_CLAMP:
  52.365 +		return ANM_EXTRAP_CLAMP;
  52.366 +	case EXTRAP_REPEAT:
  52.367 +		return ANM_EXTRAP_REPEAT;
  52.368 +	}
  52.369 +
  52.370 +	assert(0);
  52.371 +	return ANM_EXTRAP_EXTEND;
  52.372 +}
  52.373 +
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/src/xform_node.h	Thu Nov 14 05:27:09 2013 +0200
    53.3 @@ -0,0 +1,134 @@
    53.4 +/*
    53.5 +TODO: add multiple animations per node in libanim (i.e. multiple sets of tracks)
    53.6 +*/
    53.7 +#ifndef XFORM_NODE_H_
    53.8 +#define XFORM_NODE_H_
    53.9 +
   53.10 +#include <vector>
   53.11 +#include "vmath/vector.h"
   53.12 +#include "vmath/quat.h"
   53.13 +#include "vmath/matrix.h"
   53.14 +
   53.15 +enum Interp { INTERP_STEP, INTERP_LINEAR, INTERP_CUBIC };
   53.16 +enum Extrap { EXTRAP_EXTEND, EXTRAP_CLAMP, EXTRAP_REPEAT };
   53.17 +
   53.18 +struct anm_node;
   53.19 +struct anm_track;
   53.20 +
   53.21 +// XXX all time arguments are milliseconds
   53.22 +
   53.23 +class XFormNode {
   53.24 +private:
   53.25 +	struct anm_node *anm;
   53.26 +	std::vector<XFormNode*> children;
   53.27 +
   53.28 +	Interp interp;
   53.29 +	Extrap extrap;
   53.30 +
   53.31 +	Matrix4x4 local_matrix;
   53.32 +	Matrix4x4 bone_matrix;
   53.33 +
   53.34 +	XFormNode(const XFormNode &node) {}
   53.35 +	XFormNode &operator =(const XFormNode &node) { return *this; }
   53.36 +
   53.37 +public:
   53.38 +	XFormNode();
   53.39 +	virtual ~XFormNode();
   53.40 +
   53.41 +	void set_name(const char *name);
   53.42 +	const char *get_name() const;
   53.43 +
   53.44 +	void set_interpolator(Interp in);
   53.45 +	Interp get_interpolator() const;
   53.46 +	void set_extrapolator(Extrap ex);
   53.47 +	Extrap get_extrapolator() const;
   53.48 +
   53.49 +	// children management
   53.50 +	void add_child(XFormNode *child);
   53.51 +	void remove_child(XFormNode *child);
   53.52 +
   53.53 +	int get_children_count() const;
   53.54 +	XFormNode *get_child(int idx);
   53.55 +	const XFormNode *get_child(int idx) const;
   53.56 +
   53.57 +
   53.58 +	void set_position(const Vector3 &pos, long tmsec = 0);
   53.59 +	Vector3 get_node_position(long tmsec = 0) const;
   53.60 +
   53.61 +	void set_rotation(const Quaternion &quat, long tmsec = 0);
   53.62 +	Quaternion get_node_rotation(long tmsec = 0) const;
   53.63 +
   53.64 +	void set_scaling(const Vector3 &pos, long tmsec = 0);
   53.65 +	Vector3 get_node_scaling(long tmsec = 0) const;
   53.66 +
   53.67 +	// these take hierarchy into account
   53.68 +	Vector3 get_position(long tmsec = 0) const;
   53.69 +	Quaternion get_rotation(long tmsec = 0) const;
   53.70 +	Vector3 get_scaling(long tmsec = 0) const;
   53.71 +
   53.72 +	void set_pivot(const Vector3 &pivot);
   53.73 +	Vector3 get_pivot() const;
   53.74 +
   53.75 +	// the local matrix is concatenated with the regular node/anim matrix
   53.76 +	void set_local_matrix(const Matrix4x4 &mat);
   53.77 +	const Matrix4x4 &get_local_matrix() const;
   53.78 +
   53.79 +	// for bone nodes, the transformation of the bone in bind position
   53.80 +	void set_bone_matrix(const Matrix4x4 &bmat);
   53.81 +	const Matrix4x4 &get_bone_matrix() const;
   53.82 +
   53.83 +	// node transformation alone
   53.84 +	void get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const;
   53.85 +
   53.86 +	// node transformation taking hierarchy into account
   53.87 +	void get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const;
   53.88 +};
   53.89 +
   53.90 +
   53.91 +class Track {
   53.92 +private:
   53.93 +	struct anm_track *trk;
   53.94 +	Interp interp;
   53.95 +	Extrap extrap;
   53.96 +
   53.97 +public:
   53.98 +	Track();
   53.99 +	~Track();
  53.100 +
  53.101 +	Track(const Track &trk);
  53.102 +	Track &operator =(const Track &trk);
  53.103 +
  53.104 +	void set_interpolator(Interp in);
  53.105 +	Interp get_interpolator() const;
  53.106 +	void set_extrapolator(Extrap ex);
  53.107 +	Extrap get_extrapolator() const;
  53.108 +
  53.109 +	void set_default(double def);
  53.110 +
  53.111 +	void set_value(float val, long tmsec = 0);
  53.112 +	float get_value(long tmsec = 0) const;
  53.113 +
  53.114 +	// the same as get_value
  53.115 +	float operator ()(long tmsec = 0) const;
  53.116 +};
  53.117 +
  53.118 +class Track3 {
  53.119 +private:
  53.120 +	Track track[3];
  53.121 +
  53.122 +public:
  53.123 +	void set_interpolator(Interp in);
  53.124 +	Interp get_interpolator() const;
  53.125 +	void set_extrapolator(Extrap ex);
  53.126 +	Extrap get_extrapolator() const;
  53.127 +
  53.128 +	void set_default(const Vector3 &def);
  53.129 +
  53.130 +	void set_value(const Vector3 &val, long tmsec = 0);
  53.131 +	Vector3 get_value(long tmsec = 0) const;
  53.132 +
  53.133 +	// the same as get_value
  53.134 +	Vector3 operator ()(long tmsec = 0) const;
  53.135 +};
  53.136 +
  53.137 +#endif	/* XFORM_NODE_H_ */