Move OBJ to a separate repo
This commit is contained in:
commit
81861157ab
7
LICENSE.md
Normal file
7
LICENSE.md
Normal file
@ -0,0 +1,7 @@
|
||||
Copyright (c) 2006,2013,2014 Robert Kooima
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
279
README.md
Normal file
279
README.md
Normal file
@ -0,0 +1,279 @@
|
||||
# obj
|
||||
|
||||
`obj` loads, manipulates, optimizes, renders, and stores 3D geometry using the Wavefront OBJ file format. The renderer uses the OpenGL 3.2 Core Profile, making it compatible with OpenGL versions 3 and 4, OpenGL ES 2.0, and also commonly-available extended implementations of OpenGL 2.1.
|
||||
|
||||
- [obj.c](obj.c)
|
||||
- [obj.h](obj.h)
|
||||
|
||||
An OBJ file consists of sets of *materials*, *vertices*, and *surfaces*. A surface consists of sets of *polygons* and *lines* with a reference to a material to be used when rendering them. A polygon is a triplet of references to vertices in the file, and a line is a pair of references to vertices.
|
||||
|
||||
OBJ files are referenced using pointers to type `obj`. The elements within the OBJ are referenced by integer index. These indices work much like a file or socket descriptor. The internal geometry representation is not accessible to the application. All operations on geometry are performed using the API documented here.
|
||||
|
||||
## Compilation
|
||||
|
||||
To use this module, simply link it with your own code. The renderer requires OpenGL. Linux and Windows compilation also requires [GLEW](http://glew.sourceforge.net/)...
|
||||
|
||||
cc -o program program.c obj.c -lGLEW -lGL -lm
|
||||
|
||||
Though OSX's native OpenGL support suffices...
|
||||
|
||||
cc -o program program.c obj.c -framework OpenGL -lm
|
||||
|
||||
If used only to process OBJ files and not to render them, the OpenGL dependency may be eliminated by defining `CONF_NO_GL`.
|
||||
|
||||
cc -o program program.c obj.c -DCONF_NO_GL -lm
|
||||
|
||||
## Quickstart
|
||||
|
||||
These code fragments implement the common case of loading and displaying a model stored in an OBJ file. First, an OBJ pointer is declared.
|
||||
|
||||
obj *O;
|
||||
|
||||
During initialization, an `obj` structure is allocated, the OBJ file and all of its MTL files and texture images are read, and the `obj` pointer is returned.
|
||||
|
||||
O = obj_create("teapot.obj");
|
||||
|
||||
During rendering:
|
||||
|
||||
obj_render(O);
|
||||
|
||||
When no longer needed, all resources held by the `obj` data structure are released:
|
||||
|
||||
obj_delete(O);
|
||||
|
||||
## The OBJ API
|
||||
|
||||
### Top level
|
||||
|
||||
As we've just seen, the top level API for manipulation OBJ files is as follows:
|
||||
|
||||
- `obj *obj_create(const char *filename)`
|
||||
|
||||
Create a new file object, load the OBJ file named by `filename`, and return a file object. If `filename` is `NULL` then an empty file is returned.
|
||||
|
||||
- `void obj_delete(obj *O)`
|
||||
|
||||
Delete OBJ `O` and release all resources held by it.
|
||||
|
||||
### Rendering
|
||||
|
||||
- `void obj_set_vert_loc(obj *O, int u, int n, int t, int v)`
|
||||
|
||||
Set the vertex attribute locations for the tangent, normal, texture coordinate, and position. These are acquired by calling [`glGetAttribLocation`](http://www.opengl.org/sdk/docs/man/html/glGetAttribLocation.xhtml) with the intended shader program. Pass `-1` for the location of any attribue that the shader does not receive.
|
||||
|
||||
For example, if program object `program` declares `in` varibles named `vTangent`, `vNormal`, `vTexCoord` and `vPosition` then the syntax is:
|
||||
|
||||
obj_set_vert_loc(object, glGetAttribLocation(program, "vTangent"),
|
||||
glGetAttribLocation(program, "vNormal"),
|
||||
glGetAttribLocation(program, "vTexCoord"),
|
||||
glGetAttribLocation(program, "vPosition"));
|
||||
|
||||
|
||||
- `void obj_set_prop_loc(obj *O, int ki, int c, int o, int M)`
|
||||
|
||||
Set the uniform location for the color, texture sampler index, or texture transform for material property `ki`. Pass `-1` for the location of any uniform that the shader does not receive. The value of `ki` must be one of the following:
|
||||
|
||||
<table style="margin: auto">
|
||||
<tr><td><code>OBJ_KD</code></td><td>Diffuse color</td></tr>
|
||||
<tr><td><code>OBJ_KA</code></td><td>Ambient color</td></tr>
|
||||
<tr><td><code>OBJ_KE</code></td><td>Emissive color</td></tr>
|
||||
<tr><td><code>OBJ_KS</code></td><td>Specular color</td></tr>
|
||||
<tr><td><code>OBJ_NS</code></td><td>Specular exponent</td></tr>
|
||||
<tr><td><code>OBJ_KN</code></td><td>Normal</td></tr>
|
||||
</table>
|
||||
|
||||
For example, if program object `program` declares diffuse and normal samplers named `DiffuseTexture` and `NormalTexture`, but no colors, transforms, or other material properties, then the syntax is:
|
||||
|
||||
obj_set_prop_loc(object, OBJ_KD, -1, glGetUniformLocation(program, "DiffuseTexture"), -1);
|
||||
obj_set_prop_loc(object, OBJ_KN, -1, glGetUniformLocation(program, "NormalTexture"), -1);
|
||||
|
||||
The material color will be set using `glUniform4fv`, the sampler index with `glUniform1i`, and the texture transform with `glUniformMatrix4fv`.
|
||||
|
||||
- `void obj_render(obj *O)`
|
||||
|
||||
Render OBJ `O`. The polygons and lines of all surfaces are rendered using their assigned materials. Aside from materials and textures, no OpenGL state is modified. In particular, any bound vertex and fragment shaders execute as expected.
|
||||
|
||||
### Element Creation
|
||||
|
||||
- `int obj_add_mtrl(obj *O)`
|
||||
|
||||
Add a new material to OBJ `O`, returning a material index. The new material is initialized with a diffuse color of (0.8, 0.8, 0.8, 1.0), an ambient color of (0.2, 0.2, 0.2, 1.0), an emissive color of (0.0, 0.0, 0.0, 0.0), a specular color of (0.0, 0.0, 0.0, 0.0), and a specular exponent of 8.0.
|
||||
|
||||
- `int obj_add_vert(obj *O)`
|
||||
|
||||
Add a new vertex to OBJ `O`, returning a vertex index. The new vertex position, normal, and texture coordinate are initialized to zero.
|
||||
|
||||
- `int obj_add_surf(obj *O)`
|
||||
|
||||
Add a new surface to OBJ `O`, returning a surface index. The new surface is initialized to reference material index zero. If no materials are defined when this surface is rendered, the default material is applied.
|
||||
|
||||
- `int obj_add_poly(obj *O, int si)`
|
||||
|
||||
Add a new 3-sided polygon to surface `si` of OBJ `O`, returning a polygon index. The new polygon's vertex indices are initialized to zero.
|
||||
|
||||
- `int obj_add_line(obj *O, int si)`
|
||||
|
||||
Add a new line to surface `si` of OBJ `O`, returning a line index. The new line's vertex indices are initialized to zero.
|
||||
|
||||
### Element Counters
|
||||
|
||||
- `int obj_num_mtrl(const obj *O)`
|
||||
- `int obj_num_vert(const obj *O)`
|
||||
- `int obj_num_surf(const obj *O)`
|
||||
|
||||
Return the number of materials, vertices, and surfaces contained by OBJ `O`. All indices less than this number are valid indices into that file.
|
||||
|
||||
- `int obj_num_poly(const obj *O, int si)`
|
||||
- `int obj_num_line(const obj *O, int si)`
|
||||
|
||||
Return the number of polygons and lines contained by surface `si` of OBJ `O`. All indices less than this number are valid indices into that surface.
|
||||
|
||||
### Element deletion
|
||||
|
||||
Note: The element deletion API goes to great lengths to ensure that all geometry blocks are free of gaps, and that all internal references are consistent. If an application removes an element from the middle of a block then all higher-index elements are shifted down, and any references to these elements are decremented. Be aware: if an application caches element indices elsewhere, then these indices may be invalidated by a deletion operation.
|
||||
|
||||
- `void obj_del_mtrl(obj *O, int mi)`
|
||||
|
||||
Remove material `mi` from OBJ `O`. Any surfaces in OBJ `O` that reference this material will also be removed. All higher-indexed materials are shifted down. Surfaces that refer to higher-indexed materials have their material indices decremented.
|
||||
|
||||
- `void obj_del_vert(obj *O, int vi)`
|
||||
|
||||
Remove vertex `vi` from OBJ `O`. Any polygons or lines referencing this vertex in any surface of OBJ `O` are also removed. Higher-indexed vertices are shifted down. Polygons and lines that refer to higher-index vertices have their vertex indices decremented.
|
||||
|
||||
- `void obj_del_poly(obj *O, int si, int pi)`
|
||||
|
||||
Remove polygon `pi` from surface `si` of OBJ `O`. Higher-indexed polygons are shifted down. Vertices referenced by polygon `pi` are *not* removed, as they may be refered-to by other polygons or lines.
|
||||
|
||||
- `void obj_del_line(obj *O, int si, int li)`
|
||||
|
||||
Remove line `li` from surface `si` of OBJ `O`. Higher-indexed lines are shifted down. Vertices referenced by line `li` are *not* removed, as they may be refered-to by other polygons or lines.
|
||||
|
||||
- `void obj_del_surf(obj *O, int si)`
|
||||
|
||||
Remove surface `si` from OBJ `O`. All polygons and lines contained in this surface are also removed. Vertices in OBJ `O` referenced by these polygons and lines are *not* removed. Higher-indexed surfaces are shifted down.
|
||||
|
||||
### Entity Manipulators
|
||||
|
||||
- `void obj_set_mtrl_name(obj *O, int mi, const char *name)`
|
||||
|
||||
Set the name of material `mi` in OBJ `O`. This name is the means by which materials defined in an MTL file are referenced from within an OBJ file. Materials without assigned names are referenced as "default." If materials are not assigned unique names, then then the surface-material mapping is not guaranteed to be preserved when a file is written.
|
||||
|
||||
- `void obj_set_mtrl_map(obj *O, int mi, int ki, const char *image)`
|
||||
|
||||
Set the image map to be used for diffuse color, ambient color, emissive color, specular color, specular exponent, or normal map of material `mi` of OBJ `O`. As of this writing, the file must be given in Targa (`.TGA`) 24-bit or 32-bit format.
|
||||
|
||||
- `void obj_set_mtrl_opt(obj *O, int mi, int ki, unsigned int opt)`
|
||||
|
||||
Set the options on property `ki` of material `mi` in OBJ `O`.
|
||||
|
||||
<a name="option" id="option"></a>The `opt` argument gives a bitmap of options to be enabled. The following options are defined. Yeah, there's only one right now.
|
||||
|
||||
<table style="margin: auto">
|
||||
<tr><td><code>OBJ_OPT_CLAMP</code></td><td>Clamp the property map. Default is to repeat.</td></tr>
|
||||
</table>
|
||||
|
||||
- `void obj_set_mtrl_c(obj *O, int mi, int ki, const float c[4])`
|
||||
|
||||
Set the diffuse color, ambient color, emissive color, specular color, or specular exponent of material `mi` of OBJ `O`. The `ki` argument selects the property to be set. Note that the MTL file format supports RGBA diffuse color, but only RGB ambient, and specular colors. So while ambient and specular alpha values will be rendered normally, they cannot be stored in an MTL file, and will always default to 1.0 when a material is loaded. The specular exponent is stored and applied as a scalar.
|
||||
|
||||
- `void obj_set_mtrl_o(obj *O, int mi, int ki, const float o[3])`
|
||||
|
||||
Set the texture coordinate offset for property map `ki` of material `mi` in OBJ `O`.
|
||||
|
||||
- `void obj_set_mtrl_s(obj *O, int mi, int ki, const float s[3])`
|
||||
|
||||
Set the texture coordinate scale for property map `ki` of material `mi` in OBJ `O`.
|
||||
|
||||
- `void obj_set_vert_v(obj *O, int vi, const float *v)`
|
||||
- `void obj_set_vert_t(obj *O, int vi, const float *t)`
|
||||
- `void obj_set_vert_n(obj *O, int vi, const float *n)`
|
||||
|
||||
Set the 3D position, 2D texture coordinate, or 3D normal vector of vertex `vi` of file fi.
|
||||
|
||||
- `void obj_set_poly(obj *O, int si, int pi, const int *vi)`
|
||||
|
||||
Set the triplet of vertex indices defining polygon `pi` in surface `si` of OBJ `O`.
|
||||
|
||||
- `void obj_set_line(obj *O, int si, int li, const int *vi)`
|
||||
|
||||
Set the pair of vertex indices defining line `li` in surface `si` of OBJ `O`.
|
||||
|
||||
- `void obj_set_surf(obj *O, int si, int mi)`
|
||||
|
||||
Set the material index of surface `si` of OBJ `O`
|
||||
|
||||
### Entity Query
|
||||
|
||||
- `const char *obj_get_mtrl_name(const obj *O, int mi)`
|
||||
|
||||
Return the name of material `mi` of OBJ `O`.
|
||||
|
||||
- `unsigned int obj_get_mtrl_map(const obj *O, int mi, int ki)`
|
||||
|
||||
Return the property map `ki` of material `mi` of OBJ `O`. The returned value is an OpenGL texture object that may be manipulated normally using the OpenGL API.
|
||||
|
||||
- `unsigned int obj_get_mtrl_opt(const obj *O, int mi, int ki)`
|
||||
|
||||
Return the bitmap of options set on the property map `ki` of material `mi` of OBJ `O`.
|
||||
|
||||
- `void obj_get_mtrl_c(const obj *O, int mi, int ki, float *c)`
|
||||
|
||||
Return the RGBA color of property `ki` of material `mi` in OBJ `O`.
|
||||
|
||||
- `void obj_get_mtrl_o(const obj *O, int mi, int ki, float *o)`
|
||||
|
||||
Return the 3D texture coordinate offset of property map `ki` of material `mi` in OBJ `O`. (This value *is* 3D despite the texture coordinates being 2D.)
|
||||
|
||||
- `void obj_get_mtrl_s(const obj *O, int mi, int ki, float *s)`
|
||||
|
||||
Return the 3D texture coordinate scale of property map `ki` of material `mi` in OBJ `O`. (This value *is* 3D despite the texture coordinates being 2D.)
|
||||
|
||||
- `void obj_get_vert_v(const obj *O, int vi, float *v)`
|
||||
- `void obj_get_vert_t(const obj *O, int vi, float *t)`
|
||||
- `void obj_get_vert_n(const obj *O, int vi, float *n)`
|
||||
|
||||
Return the 3D position, 2D texture coordinate, or 3D normal vector of vertex `vi` of OBJ `O`.
|
||||
|
||||
- `void obj_get_poly(const obj *O, int si, int pi, int *vi)`
|
||||
|
||||
Return the triplet of indices defining polygon `pi` in surface `si` of OBJ `O`.
|
||||
|
||||
- `void obj_get_line(const obj *O, int si, int li, int *vi)`
|
||||
|
||||
Return the pair of indices defining line `li` in surface `si` of OBJ `O`.
|
||||
|
||||
- `int obj_get_surf(const obj *O, int si)`
|
||||
|
||||
Return the material index of surface `si` of OBJ `O`.
|
||||
|
||||
### OBJ I/O
|
||||
|
||||
#### Processing
|
||||
|
||||
- `void obj_proc(obj *O)`
|
||||
|
||||
Process OBJ `O` for rendering. All normal vectors are normalized and a tangent vector is computed for each vertex using its normal vector and texture coordinate. Surfaces are sorted in order of increasing transparency in order to correct blending order.
|
||||
|
||||
- `float obj_acmr(obj *O, int qc)`
|
||||
|
||||
Compute the *average cache miss ratio* (ACMR) for OBJ `O` using a cache size of `qc`. The ACMR gives a measure of the effective geometry complexity of a model. It is the average number of vertices processed per triangle, taking into account post-transform vertex caching. In the worst case scenario, an unoptimized model will have an ACMR of 3. A well-optimized, well-behaved model can have an ACMR as low as 0.5, though in practice, any value less than one is excellent.
|
||||
|
||||
- `void obj_sort(obj *O, int qc)`
|
||||
|
||||
Sort the triangles of OBJ `O` in an attempt to reduce the model's average cache miss ratio, as rendered using a vertex cache of size `qc`. A sorted model may be written to a file and will remain optimized when subsequently read.
|
||||
|
||||
Proper selection of `qc` is crucial. Overestimating the cache size will result in bad performance. It is safe to assume a cache size of 16. Recent video hardware provides cache sizes up to 32. Average-case analysis indicates that future video hardware is unlikely to increase cache size far beyond 32.
|
||||
|
||||
Optimal sorting is NP-complete. This implementation is fast (linear in the number of triangles) but not optimal. There is no guarantee that a sorted model will have a lower ACMR than the original unsorted model. Paranoid applications should confirm that sorting reduces the ACMR and reload the model if it does not.
|
||||
|
||||
#### Exporting
|
||||
|
||||
- `void obj_write(obj *O, const char *obj, const char *mtl, int prec)`
|
||||
|
||||
Write all geometry of OBJ `O` to a file named by `obj`. Write all materials of OBJ `O` to a file named by `mtl`. If either file name argument is `NULL` then the corresponding file is not written. The `prec` argument gives the number of digits of precision to write for each floating point value. This can have a significant impact on the resulting file size.
|
||||
|
||||
Note: if geometry is read from one file and written to another then there is no guarantee that the source and destination files are identical. Shared normals and texture coordinates are duplicated per vertex. The number of position, normal, and texture coordinate specifications equal the number of vertices in the file.
|
||||
|
||||
All face specifications are of the form "`f i/i/i j/j/j k/k/k`" for some vertex indices `i`, `j`, `k`. All line specifications are of the form "`l i/i j/j`" for some vertex indices `i`, `j`. All vertex indices are positive, counting from the beginning of the file.
|
||||
|
||||
Any groups specified in the source OBJ are discarded, and the output OBJ is organized by material. Unused specifications in OBJ and MTL files (curves, merging groups, etc) are omitted. Smoothing groups are omitted, and the smoothed normals for each vertex are inserted instead. All comments are stripped.
|
BIN
etc/Chest-diffuse.tga
Normal file
BIN
etc/Chest-diffuse.tga
Normal file
Binary file not shown.
After Width: | Height: | Size: 768 KiB |
BIN
etc/Chest-normal.tga
Normal file
BIN
etc/Chest-normal.tga
Normal file
Binary file not shown.
After Width: | Height: | Size: 768 KiB |
BIN
etc/Chest-specular.tga
Normal file
BIN
etc/Chest-specular.tga
Normal file
Binary file not shown.
After Width: | Height: | Size: 768 KiB |
13
etc/Chest.mtl
Normal file
13
etc/Chest.mtl
Normal file
@ -0,0 +1,13 @@
|
||||
# Exported from Wings 3D 1.5.1
|
||||
newmtl Chest
|
||||
Ns 100.0
|
||||
d 1.0
|
||||
illum 2
|
||||
Kd 1.0 1.0 1.0
|
||||
Ka 1.0 1.0 1.0
|
||||
Ks 1.0 1.0 1.0
|
||||
Ke 0.0 0.0 0.0
|
||||
map_Kd Chest-diffuse.tga
|
||||
map_Ks Chest-specular.tga
|
||||
map_Kn Chest-normal.tga
|
||||
|
2698
etc/Chest.obj
Normal file
2698
etc/Chest.obj
Normal file
File diff suppressed because it is too large
Load Diff
253
etc/GLDemonstration.hpp
Normal file
253
etc/GLDemonstration.hpp
Normal file
@ -0,0 +1,253 @@
|
||||
// Copyright (c) 2014 Robert Kooima
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef GLDEMONSTRATION_HPP
|
||||
#define GLDEMONSTRATION_HPP
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace gl
|
||||
{
|
||||
class demonstration
|
||||
{
|
||||
public:
|
||||
|
||||
/// Initialize an SDL OpenGL window with the given title and size.
|
||||
|
||||
demonstration(const char *title, int w, int h) :
|
||||
width(w),
|
||||
height(h),
|
||||
running(false),
|
||||
sun_rotation(-90, 0),
|
||||
drag_sun_rotation(false),
|
||||
drag_cam_rotation(false)
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_VIDEO) == 0)
|
||||
{
|
||||
int x = SDL_WINDOWPOS_CENTERED;
|
||||
int y = SDL_WINDOWPOS_CENTERED;
|
||||
int f = SDL_WINDOW_OPENGL;
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
|
||||
SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
|
||||
if ((window = SDL_CreateWindow(title, x, y, w, h, f)))
|
||||
{
|
||||
context = SDL_GL_CreateContext(window);
|
||||
running = true;
|
||||
#ifdef GLEW_VERSION
|
||||
glewExperimental = GL_TRUE;
|
||||
glewInit();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dispatch SDL events.
|
||||
|
||||
void run()
|
||||
{
|
||||
SDL_Event e;
|
||||
|
||||
while (running)
|
||||
{
|
||||
while (SDL_PollEvent(&e))
|
||||
switch (e.type)
|
||||
{
|
||||
case SDL_MOUSEBUTTONDOWN: button(e.button.button, true); break;
|
||||
case SDL_MOUSEBUTTONUP: button(e.button.button, false); break;
|
||||
case SDL_MOUSEMOTION: motion(e.motion.x, e.motion.y); break;
|
||||
case SDL_KEYDOWN: if (e.key.repeat == 0) key(e.key.keysym.scancode, true); break;
|
||||
case SDL_KEYUP: if (e.key.repeat == 0) key(e.key.keysym.scancode, false); break;
|
||||
case SDL_QUIT: running = false; break;
|
||||
}
|
||||
|
||||
step();
|
||||
draw();
|
||||
SDL_GL_SwapWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
/// Finalize the SDL OpenGL window.
|
||||
|
||||
virtual ~demonstration()
|
||||
{
|
||||
if (context) SDL_GL_DeleteContext(context);
|
||||
if (window) SDL_DestroyWindow(window);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// Draw the scene.
|
||||
|
||||
virtual void draw()
|
||||
{
|
||||
}
|
||||
|
||||
/// Animate.
|
||||
|
||||
virtual void step()
|
||||
{
|
||||
mat3 N = normal(inverse(view()));
|
||||
cam_position = cam_position + N * cam_velocity / 30.0;
|
||||
}
|
||||
|
||||
/// Handle a mouse button press or release.
|
||||
|
||||
virtual void button(int button, bool down)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
drag_cam_rotation = down;
|
||||
prev_cam_rotation = cam_rotation;
|
||||
break;
|
||||
|
||||
case SDL_BUTTON_RIGHT:
|
||||
drag_sun_rotation = down;
|
||||
prev_sun_rotation = sun_rotation;
|
||||
break;
|
||||
}
|
||||
prev_x = curr_x;
|
||||
prev_y = curr_y;
|
||||
}
|
||||
|
||||
/// Handle mouse pointer motion.
|
||||
|
||||
virtual void motion(int x, int y)
|
||||
{
|
||||
GLfloat dy = GLfloat(y - prev_y) / height;
|
||||
GLfloat dx = GLfloat(x - prev_x) / height;
|
||||
|
||||
if (drag_cam_rotation)
|
||||
{
|
||||
cam_rotation[0] = prev_cam_rotation[0] + 90.0 * dy;
|
||||
cam_rotation[1] = prev_cam_rotation[1] + 180.0 * dx;
|
||||
|
||||
if (cam_rotation[0] > 90) cam_rotation[0] = 90;
|
||||
if (cam_rotation[0] < -90) cam_rotation[0] = -90;
|
||||
if (cam_rotation[1] > 180) cam_rotation[1] -= 360;
|
||||
if (cam_rotation[1] < -180) cam_rotation[1] += 360;
|
||||
}
|
||||
if (drag_sun_rotation)
|
||||
{
|
||||
sun_rotation[0] = prev_sun_rotation[0] + 90.0 * dy;
|
||||
sun_rotation[1] = prev_sun_rotation[1] + 180.0 * dx;
|
||||
|
||||
if (sun_rotation[0] > 90) sun_rotation[0] = 90;
|
||||
if (sun_rotation[0] < -90) sun_rotation[0] = -90;
|
||||
if (sun_rotation[1] > 180) sun_rotation[1] -= 360;
|
||||
if (sun_rotation[1] < -180) sun_rotation[1] += 360;
|
||||
}
|
||||
curr_x = x;
|
||||
curr_y = y;
|
||||
}
|
||||
|
||||
/// Handle a key press or release.
|
||||
|
||||
virtual void key(int key, bool down)
|
||||
{
|
||||
if (down)
|
||||
switch (key)
|
||||
{
|
||||
case SDL_SCANCODE_A: cam_velocity[0] -= 1.0; break;
|
||||
case SDL_SCANCODE_D: cam_velocity[0] += 1.0; break;
|
||||
case SDL_SCANCODE_C: cam_velocity[1] -= 1.0; break;
|
||||
case SDL_SCANCODE_SPACE: cam_velocity[1] += 1.0; break;
|
||||
case SDL_SCANCODE_W: cam_velocity[2] -= 1.0; break;
|
||||
case SDL_SCANCODE_S: cam_velocity[2] += 1.0; break;
|
||||
}
|
||||
else
|
||||
switch (key)
|
||||
{
|
||||
case SDL_SCANCODE_A: cam_velocity[0] += 1.0; break;
|
||||
case SDL_SCANCODE_D: cam_velocity[0] -= 1.0; break;
|
||||
case SDL_SCANCODE_C: cam_velocity[1] += 1.0; break;
|
||||
case SDL_SCANCODE_SPACE: cam_velocity[1] -= 1.0; break;
|
||||
case SDL_SCANCODE_W: cam_velocity[2] += 1.0; break;
|
||||
case SDL_SCANCODE_S: cam_velocity[2] -= 1.0; break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the current projection matrix.
|
||||
|
||||
mat4 projection(GLfloat n=0.10f, GLfloat f=100.f) const
|
||||
{
|
||||
const GLfloat a = GLfloat(width) / GLfloat(height);
|
||||
return perspective(to_radians(60.f), a, n, f);
|
||||
}
|
||||
|
||||
/// Return the current view matrix.
|
||||
|
||||
mat4 view() const
|
||||
{
|
||||
return xrotation(to_radians(cam_rotation[0]))
|
||||
* yrotation(to_radians(cam_rotation[1]))
|
||||
* translation(-cam_position);
|
||||
}
|
||||
|
||||
/// Return the current light vector.
|
||||
|
||||
vec4 light() const
|
||||
{
|
||||
return xrotation(to_radians(sun_rotation[0]))
|
||||
* yrotation(to_radians(sun_rotation[1])) * vec4(0, 0, 1, 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
int width;
|
||||
int height;
|
||||
bool running;
|
||||
|
||||
vec3 cam_position;
|
||||
vec3 cam_velocity;
|
||||
vec2 cam_rotation;
|
||||
vec2 sun_rotation;
|
||||
|
||||
private:
|
||||
|
||||
bool drag_sun_rotation;
|
||||
bool drag_cam_rotation;
|
||||
vec2 prev_sun_rotation;
|
||||
vec2 prev_cam_rotation;
|
||||
int prev_x;
|
||||
int prev_y;
|
||||
int curr_x;
|
||||
int curr_y;
|
||||
|
||||
SDL_Window *window;
|
||||
SDL_GLContext context;
|
||||
};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
821
etc/GLFundamentals.hpp
Normal file
821
etc/GLFundamentals.hpp
Normal file
@ -0,0 +1,821 @@
|
||||
// Copyright (c) 2013 Robert Kooima
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef GLFUNDAMENTALS_HPP
|
||||
#define GLFUNDAMENTALS_HPP
|
||||
|
||||
/// This header provides the basic functionality necessary to make effective use
|
||||
/// of modern OpenGL (e.g. OpenGL 3.2 Core Profile or OpenGL ES 2.0 or later).
|
||||
///
|
||||
/// Given the lack of fixed functionality and matrix handling, all applications
|
||||
/// will need to load and compile shaders and perform matrix arithmetic. Thus,
|
||||
/// these capabilities are provided here.
|
||||
///
|
||||
/// Basic TGA read and write procedures for texture handling are also provided.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <OpenGL/gl3.h>
|
||||
#else
|
||||
# include <GL/glew.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define GL_CHECK_ERROR() ((void) 0)
|
||||
#else
|
||||
# define GL_CHECK_ERROR() check(__FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
namespace gl
|
||||
{
|
||||
inline void check(const char *file, int line, FILE *stream = stderr)
|
||||
{
|
||||
switch (glGetError())
|
||||
{
|
||||
case GL_INVALID_ENUM:
|
||||
fprintf(stream, "%s:%d: Invalid Enum\n", file, line); abort();
|
||||
case GL_INVALID_VALUE:
|
||||
fprintf(stream, "%s:%d: Invalid Value\n", file, line); abort();
|
||||
case GL_INVALID_OPERATION:
|
||||
fprintf(stream, "%s:%d: Invalid Operation\n", file, line); abort();
|
||||
case GL_OUT_OF_MEMORY:
|
||||
fprintf(stream, "%s:%d: Out of Memory\n", file, line); abort();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// 2-component 32-bit floating point vector.
|
||||
|
||||
struct vec2
|
||||
{
|
||||
GLfloat v[2];
|
||||
|
||||
vec2(GLfloat x=0, GLfloat y=0)
|
||||
{
|
||||
v[0] = x;
|
||||
v[1] = y;
|
||||
}
|
||||
|
||||
const GLfloat& operator[](int i) const { return v[i]; }
|
||||
GLfloat& operator[](int i) { return v[i]; }
|
||||
|
||||
operator const GLfloat*() const
|
||||
{
|
||||
return const_cast<GLfloat *>(&v[0]);
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// 3-component 32-bit floating point vector.
|
||||
|
||||
struct vec3
|
||||
{
|
||||
GLfloat v[3];
|
||||
|
||||
vec3(GLfloat x=0, GLfloat y=0, GLfloat z=0)
|
||||
{
|
||||
v[0] = x;
|
||||
v[1] = y;
|
||||
v[2] = z;
|
||||
}
|
||||
vec3(const vec2& a, GLfloat b=0)
|
||||
{
|
||||
v[0] = a[0];
|
||||
v[1] = a[1];
|
||||
v[2] = b;
|
||||
}
|
||||
|
||||
const GLfloat& operator[](int i) const { return v[i]; }
|
||||
GLfloat& operator[](int i) { return v[i]; }
|
||||
|
||||
operator const GLfloat*() const
|
||||
{
|
||||
return const_cast<GLfloat *>(&v[0]);
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// 4-component 32-bit floating point vector.
|
||||
|
||||
struct vec4
|
||||
{
|
||||
GLfloat v[4];
|
||||
|
||||
vec4(GLfloat x=0, GLfloat y=0, GLfloat z=0, GLfloat w=0)
|
||||
{
|
||||
v[0] = x;
|
||||
v[1] = y;
|
||||
v[2] = z;
|
||||
v[3] = w;
|
||||
}
|
||||
vec4(const vec3& a, GLfloat b=0)
|
||||
{
|
||||
v[0] = a[0];
|
||||
v[1] = a[1];
|
||||
v[2] = a[2];
|
||||
v[3] = b;
|
||||
}
|
||||
|
||||
const GLfloat& operator[](int i) const { return v[i]; }
|
||||
GLfloat& operator[](int i) { return v[i]; }
|
||||
|
||||
operator const GLfloat*() const
|
||||
{
|
||||
return const_cast<GLfloat *>(&v[0]);
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Row-wise 3x3 32-bit floating point matrix.
|
||||
|
||||
struct mat3
|
||||
{
|
||||
vec3 M[3];
|
||||
|
||||
mat3(GLfloat m00=1, GLfloat m01=0, GLfloat m02=0,
|
||||
GLfloat m10=0, GLfloat m11=1, GLfloat m12=0,
|
||||
GLfloat m20=0, GLfloat m21=0, GLfloat m22=1)
|
||||
{
|
||||
M[0] = vec3(m00, m01, m02);
|
||||
M[1] = vec3(m10, m11, m12);
|
||||
M[2] = vec3(m20, m21, m22);
|
||||
}
|
||||
|
||||
const vec3& operator[](int i) const { return M[i]; }
|
||||
vec3& operator[](int i) { return M[i]; }
|
||||
|
||||
operator const GLfloat*() const
|
||||
{
|
||||
return const_cast<GLfloat *>(&M[0][0]);
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Row-wise 4x4 32-bit floating point matrix.
|
||||
|
||||
struct mat4
|
||||
{
|
||||
vec4 M[4];
|
||||
|
||||
mat4(GLfloat m00=0, GLfloat m01=0, GLfloat m02=0, GLfloat m03=0,
|
||||
GLfloat m10=0, GLfloat m11=0, GLfloat m12=0, GLfloat m13=0,
|
||||
GLfloat m20=0, GLfloat m21=0, GLfloat m22=0, GLfloat m23=0,
|
||||
GLfloat m30=0, GLfloat m31=0, GLfloat m32=0, GLfloat m33=0)
|
||||
{
|
||||
M[0] = vec4(m00, m01, m02, m03);
|
||||
M[1] = vec4(m10, m11, m12, m13);
|
||||
M[2] = vec4(m20, m21, m22, m23);
|
||||
M[3] = vec4(m30, m31, m32, m33);
|
||||
}
|
||||
|
||||
const vec4& operator[](int i) const { return M[i]; }
|
||||
vec4& operator[](int i) { return M[i]; }
|
||||
|
||||
operator const GLfloat*() const
|
||||
{
|
||||
return const_cast<GLfloat *>(&M[0][0]);
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Convert an angle in degrees to an angle in radians.
|
||||
|
||||
inline GLfloat to_radians(GLfloat degrees)
|
||||
{
|
||||
return degrees * 0.01745329;
|
||||
}
|
||||
|
||||
/// Convent an angle in radians to an angle in degrees.
|
||||
|
||||
inline GLfloat to_degrees(GLfloat radians)
|
||||
{
|
||||
return radians * 57.2957795;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Calculate the 3-component negation of v.
|
||||
|
||||
inline vec3 operator-(const vec3& v)
|
||||
{
|
||||
return vec3(-v[0], -v[1], -v[2]);
|
||||
}
|
||||
|
||||
/// Calculate the 3-component sum of v and w.
|
||||
|
||||
inline vec3 operator+(const vec3& v, const vec3& w)
|
||||
{
|
||||
return vec3(v[0] + w[0], v[1] + w[1], v[2] + w[2]);
|
||||
}
|
||||
|
||||
/// Calculate the 3-component difference of v and w.
|
||||
|
||||
inline vec3 operator-(const vec3& v, const vec3& w)
|
||||
{
|
||||
return vec3(v[0] - w[0], v[1] - w[1], v[2] - w[2]);
|
||||
}
|
||||
|
||||
/// Calculate the 3-component scalar quotient of v and k.
|
||||
|
||||
inline vec3 operator/(const vec3& v, GLfloat k)
|
||||
{
|
||||
return vec3(v[0] / k, v[1] / k, v[2] / k);
|
||||
}
|
||||
|
||||
/// Calculate the 3-component scalar product of v and k.
|
||||
|
||||
inline vec3 operator*(const vec3& v, GLfloat k)
|
||||
{
|
||||
return vec3(v[0] * k, v[1] * k, v[2] * k);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Calculate the 3-component dot product of v and w.
|
||||
|
||||
inline GLfloat operator*(const vec3& v, const vec3& w)
|
||||
{
|
||||
return v[0] * w[0] + v[1] * w[1] + v[2] * w[2];
|
||||
}
|
||||
|
||||
/// Calculate the 4-component dot product of v and w.
|
||||
|
||||
inline GLfloat operator*(const vec4& v, const vec4& w)
|
||||
{
|
||||
return v[0] * w[0] + v[1] * w[1] + v[2] * w[2] + v[3] * w[3];
|
||||
}
|
||||
|
||||
/// Calculate the 3-component transform of vector v by matrix A.
|
||||
|
||||
inline vec3 operator*(const mat3& A, const vec3& v)
|
||||
{
|
||||
return vec3(A[0] * v, A[1] * v, A[2] * v);
|
||||
}
|
||||
|
||||
/// Calculate the 4-component transform of vector v by matrix A.
|
||||
|
||||
inline vec4 operator*(const mat4& A, const vec4& v)
|
||||
{
|
||||
return vec4(A[0] * v, A[1] * v, A[2] * v, A[3] * v);
|
||||
}
|
||||
|
||||
/// Calculate the 3x3 matrix product of A and B.
|
||||
|
||||
inline mat3 operator*(const mat3& A, const mat3& B)
|
||||
{
|
||||
mat3 M;
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
M[i][j] = A[i][0] * B[0][j]
|
||||
+ A[i][1] * B[1][j]
|
||||
+ A[i][2] * B[2][j];
|
||||
return M;
|
||||
}
|
||||
|
||||
/// Calculate the 4x4 matrix product of A and B.
|
||||
|
||||
inline mat4 operator*(const mat4& A, const mat4& B)
|
||||
{
|
||||
mat4 M;
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
M[i][j] = A[i][0] * B[0][j]
|
||||
+ A[i][1] * B[1][j]
|
||||
+ A[i][2] * B[2][j]
|
||||
+ A[i][3] * B[3][j];
|
||||
return M;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Return the transpose of a 3x3 matrix.
|
||||
|
||||
inline mat3 transpose(const mat3& A)
|
||||
{
|
||||
mat3 M;
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
M[i][j] = A[j][i];
|
||||
return M;
|
||||
}
|
||||
|
||||
/// Return the transpose of a 4x4 matrix.
|
||||
|
||||
inline mat4 transpose(const mat4& A)
|
||||
{
|
||||
mat4 M;
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
M[i][j] = A[j][i];
|
||||
return M;
|
||||
}
|
||||
|
||||
/// Return the inverse of 4x4 matrix.
|
||||
|
||||
inline mat4 inverse(const mat4& A)
|
||||
{
|
||||
mat4 T;
|
||||
|
||||
T[0][0] = +(A[1][1] * (A[2][2] * A[3][3] - A[3][2] * A[2][3]) -
|
||||
A[1][2] * (A[2][1] * A[3][3] - A[3][1] * A[2][3]) +
|
||||
A[1][3] * (A[2][1] * A[3][2] - A[3][1] * A[2][2]));
|
||||
T[0][1] = -(A[1][0] * (A[2][2] * A[3][3] - A[3][2] * A[2][3]) -
|
||||
A[1][2] * (A[2][0] * A[3][3] - A[3][0] * A[2][3]) +
|
||||
A[1][3] * (A[2][0] * A[3][2] - A[3][0] * A[2][2]));
|
||||
T[0][2] = +(A[1][0] * (A[2][1] * A[3][3] - A[3][1] * A[2][3]) -
|
||||
A[1][1] * (A[2][0] * A[3][3] - A[3][0] * A[2][3]) +
|
||||
A[1][3] * (A[2][0] * A[3][1] - A[3][0] * A[2][1]));
|
||||
T[0][3] = -(A[1][0] * (A[2][1] * A[3][2] - A[3][1] * A[2][2]) -
|
||||
A[1][1] * (A[2][0] * A[3][2] - A[3][0] * A[2][2]) +
|
||||
A[1][2] * (A[2][0] * A[3][1] - A[3][0] * A[2][1]));
|
||||
|
||||
T[1][0] = -(A[0][1] * (A[2][2] * A[3][3] - A[3][2] * A[2][3]) -
|
||||
A[0][2] * (A[2][1] * A[3][3] - A[3][1] * A[2][3]) +
|
||||
A[0][3] * (A[2][1] * A[3][2] - A[3][1] * A[2][2]));
|
||||
T[1][1] = +(A[0][0] * (A[2][2] * A[3][3] - A[3][2] * A[2][3]) -
|
||||
A[0][2] * (A[2][0] * A[3][3] - A[3][0] * A[2][3]) +
|
||||
A[0][3] * (A[2][0] * A[3][2] - A[3][0] * A[2][2]));
|
||||
T[1][2] = -(A[0][0] * (A[2][1] * A[3][3] - A[3][1] * A[2][3]) -
|
||||
A[0][1] * (A[2][0] * A[3][3] - A[3][0] * A[2][3]) +
|
||||
A[0][3] * (A[2][0] * A[3][1] - A[3][0] * A[2][1]));
|
||||
T[1][3] = +(A[0][0] * (A[2][1] * A[3][2] - A[3][1] * A[2][2]) -
|
||||
A[0][1] * (A[2][0] * A[3][2] - A[3][0] * A[2][2]) +
|
||||
A[0][2] * (A[2][0] * A[3][1] - A[3][0] * A[2][1]));
|
||||
|
||||
T[2][0] = +(A[0][1] * (A[1][2] * A[3][3] - A[3][2] * A[1][3]) -
|
||||
A[0][2] * (A[1][1] * A[3][3] - A[3][1] * A[1][3]) +
|
||||
A[0][3] * (A[1][1] * A[3][2] - A[3][1] * A[1][2]));
|
||||
T[2][1] = -(A[0][0] * (A[1][2] * A[3][3] - A[3][2] * A[1][3]) -
|
||||
A[0][2] * (A[1][0] * A[3][3] - A[3][0] * A[1][3]) +
|
||||
A[0][3] * (A[1][0] * A[3][2] - A[3][0] * A[1][2]));
|
||||
T[2][2] = +(A[0][0] * (A[1][1] * A[3][3] - A[3][1] * A[1][3]) -
|
||||
A[0][1] * (A[1][0] * A[3][3] - A[3][0] * A[1][3]) +
|
||||
A[0][3] * (A[1][0] * A[3][1] - A[3][0] * A[1][1]));
|
||||
T[2][3] = -(A[0][0] * (A[1][1] * A[3][2] - A[3][1] * A[1][2]) -
|
||||
A[0][1] * (A[1][0] * A[3][2] - A[3][0] * A[1][2]) +
|
||||
A[0][2] * (A[1][0] * A[3][1] - A[3][0] * A[1][1]));
|
||||
|
||||
T[3][0] = -(A[0][1] * (A[1][2] * A[2][3] - A[2][2] * A[1][3]) -
|
||||
A[0][2] * (A[1][1] * A[2][3] - A[2][1] * A[1][3]) +
|
||||
A[0][3] * (A[1][1] * A[2][2] - A[2][1] * A[1][2]));
|
||||
T[3][1] = +(A[0][0] * (A[1][2] * A[2][3] - A[2][2] * A[1][3]) -
|
||||
A[0][2] * (A[1][0] * A[2][3] - A[2][0] * A[1][3]) +
|
||||
A[0][3] * (A[1][0] * A[2][2] - A[2][0] * A[1][2]));
|
||||
T[3][2] = -(A[0][0] * (A[1][1] * A[2][3] - A[2][1] * A[1][3]) -
|
||||
A[0][1] * (A[1][0] * A[2][3] - A[2][0] * A[1][3]) +
|
||||
A[0][3] * (A[1][0] * A[2][1] - A[2][0] * A[1][1]));
|
||||
T[3][3] = +(A[0][0] * (A[1][1] * A[2][2] - A[2][1] * A[1][2]) -
|
||||
A[0][1] * (A[1][0] * A[2][2] - A[2][0] * A[1][2]) +
|
||||
A[0][2] * (A[1][0] * A[2][1] - A[2][0] * A[1][1]));
|
||||
|
||||
const GLfloat d = 1 / (A[0] * T[0]);
|
||||
|
||||
return mat4(T[0][0] * d, T[1][0] * d, T[2][0] * d, T[3][0] * d,
|
||||
T[0][1] * d, T[1][1] * d, T[2][1] * d, T[3][1] * d,
|
||||
T[0][2] * d, T[1][2] * d, T[2][2] * d, T[3][2] * d,
|
||||
T[0][3] * d, T[1][3] * d, T[2][3] * d, T[3][3] * d);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Compute the length of vector v.
|
||||
|
||||
inline GLfloat length(const vec3 &v)
|
||||
{
|
||||
return sqrt(v * v);
|
||||
}
|
||||
|
||||
/// Compute the cross product of vectors v and w.
|
||||
|
||||
inline vec3 cross(const vec3& v, const vec3& w)
|
||||
{
|
||||
return vec3(v[1] * w[2] - v[2] * w[1],
|
||||
v[2] * w[0] - v[0] * w[2],
|
||||
v[0] * w[1] - v[1] * w[0]);
|
||||
}
|
||||
|
||||
/// Compute the normalization of vector v.
|
||||
|
||||
inline vec3 normalize(const vec3& v)
|
||||
{
|
||||
return v / length(v);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Return a matrix giving a rotation about X through a radians.
|
||||
|
||||
inline mat4 xrotation(GLfloat a)
|
||||
{
|
||||
return mat4(1, 0, 0, 0,
|
||||
0, cos(a), -sin(a), 0,
|
||||
0, sin(a), cos(a), 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/// Return a matrix giving a rotation about Y through a radians.
|
||||
|
||||
inline mat4 yrotation(GLfloat a)
|
||||
{
|
||||
return mat4( cos(a), 0, sin(a), 0,
|
||||
0, 1, 0, 0,
|
||||
-sin(a), 0, cos(a), 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/// Return a matrix giving a rotation about Z through a radians.
|
||||
|
||||
inline mat4 zrotation(GLfloat a)
|
||||
{
|
||||
return mat4(cos(a), -sin(a), 0, 0,
|
||||
sin(a), cos(a), 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/// Return a matrix giving a rotation about v through a radians.
|
||||
|
||||
inline mat4 rotation(const vec3& v, double a)
|
||||
{
|
||||
const vec3 u = normalize(v);
|
||||
const GLfloat s = GLfloat(sin(a));
|
||||
const GLfloat c = GLfloat(cos(a));
|
||||
|
||||
return mat4(u[0] * u[0] + (1 - u[0] * u[0]) * c,
|
||||
u[0] * u[1] + (0 - u[0] * u[1]) * c - u[2] * s,
|
||||
u[0] * u[2] + (0 - u[0] * u[2]) * c + u[1] * s,
|
||||
0,
|
||||
u[1] * u[0] + (0 - u[1] * u[0]) * c + u[2] * s,
|
||||
u[1] * u[1] + (1 - u[1] * u[1]) * c,
|
||||
u[1] * u[2] + (0 - u[1] * u[2]) * c - u[0] * s,
|
||||
0,
|
||||
u[2] * u[0] + (0 - u[2] * u[0]) * c - u[1] * s,
|
||||
u[2] * u[1] + (0 - u[2] * u[1]) * c + u[0] * s,
|
||||
u[2] * u[2] + (1 - u[2] * u[2]) * c,
|
||||
0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/// Return a matrix giving a translation along vector v.
|
||||
|
||||
inline mat4 translation(const vec3& v)
|
||||
{
|
||||
return mat4(1, 0, 0, v[0],
|
||||
0, 1, 0, v[1],
|
||||
0, 0, 1, v[2],
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/// Return a matrix giving a scale along vector v.
|
||||
|
||||
inline mat4 scale(const vec3& v)
|
||||
{
|
||||
return mat4(v[0], 0, 0, 0,
|
||||
0, v[1], 0, 0,
|
||||
0, 0, v[2], 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/// Return a matrix giving a perspective projection with field-of-view v,
|
||||
/// aspect ratio a, near clipping distance n, and far clipping distance f.
|
||||
|
||||
inline mat4 perspective(GLfloat v, GLfloat a, GLfloat n, GLfloat f)
|
||||
{
|
||||
const GLfloat y = n * tan(v / 2);
|
||||
const GLfloat x = y * a;
|
||||
|
||||
return mat4(n / x, 0, 0, 0, 0,
|
||||
n / y, 0, 0, 0, 0, (n + f) / (n - f),
|
||||
2 * (n * f) / (n - f), 0, 0, -1, 0);
|
||||
}
|
||||
|
||||
/// Return a matrix giving a perspective projection with the given left,
|
||||
/// right, bottom, top, near, and far clipping boundaries.
|
||||
|
||||
inline mat4 perspective(GLfloat l, GLfloat r,
|
||||
GLfloat b, GLfloat t,
|
||||
GLfloat n, GLfloat f)
|
||||
{
|
||||
return mat4((n + n) / (r - l), 0,
|
||||
(r + l) / (r - l), 0, 0,
|
||||
(n + n) / (t - b),
|
||||
(t + b) / (t - b), 0, 0, 0,
|
||||
(n + f) / (n - f),
|
||||
2 * (n * f) / (n - f), 0, 0, -1, 0);
|
||||
}
|
||||
|
||||
/// Return a matrix giving an orthogonal projection with the given left,
|
||||
/// right, bottom, top, near, and far clipping boundaries.
|
||||
|
||||
inline mat4 orthogonal(GLfloat l, GLfloat r,
|
||||
GLfloat b, GLfloat t,
|
||||
GLfloat n, GLfloat f)
|
||||
{
|
||||
return mat4(2 / (r - l), 0, 0, -(r + l) / (r - l), 0,
|
||||
2 / (t - b), 0, -(t + b) / (t - b), 0, 0,
|
||||
-2 / (f - n), -(f + n) / (f - n), 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/// Compute a normal matrix for the given model-view matrix by returning
|
||||
/// the transposed inverse upper 3x3 matrix of the given 4x4 matrix.
|
||||
|
||||
inline mat3 normal(const mat4& M)
|
||||
{
|
||||
const GLfloat d = M[0][0] * M[1][1] * M[2][2]
|
||||
- M[0][0] * M[1][2] * M[2][1]
|
||||
+ M[0][1] * M[1][2] * M[2][0]
|
||||
- M[0][1] * M[1][0] * M[2][2]
|
||||
+ M[0][2] * M[1][0] * M[2][1]
|
||||
- M[0][2] * M[1][1] * M[2][0];
|
||||
if (fabs(d) > 0.f)
|
||||
return mat3(-M[1][2] * M[2][1] + M[1][1] * M[2][2],
|
||||
M[1][2] * M[2][0] - M[1][0] * M[2][2],
|
||||
-M[1][1] * M[2][0] + M[1][0] * M[2][1],
|
||||
M[0][2] * M[2][1] - M[0][1] * M[2][2],
|
||||
-M[0][2] * M[2][0] + M[0][0] * M[2][2],
|
||||
M[0][1] * M[2][0] - M[0][0] * M[2][1],
|
||||
-M[0][2] * M[1][1] + M[0][1] * M[1][2],
|
||||
M[0][2] * M[1][0] - M[0][0] * M[1][2],
|
||||
-M[0][1] * M[1][0] + M[0][0] * M[1][1]);
|
||||
else
|
||||
return mat3();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct tga_head
|
||||
{
|
||||
unsigned char id_length;
|
||||
unsigned char color_map_type;
|
||||
unsigned char image_type;
|
||||
unsigned short color_map_offset;
|
||||
unsigned short color_map_length;
|
||||
unsigned char color_map_size;
|
||||
unsigned short image_x_origin;
|
||||
unsigned short image_y_origin;
|
||||
unsigned short image_width;
|
||||
unsigned short image_height;
|
||||
unsigned char image_depth;
|
||||
unsigned char image_descriptor;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
/// Write a 24 or 32-bit uncompressed true-color Targa image file. Receive
|
||||
/// the raw pixel buffer in p and width, height, and depth in w, h, and d.
|
||||
/// Return 0 on success and -1 on failure. Errno indicates the error.
|
||||
|
||||
inline int write_tga(const char *filename, int w, int h, int d, void *p)
|
||||
{
|
||||
tga_head head;
|
||||
|
||||
memset(&head, 0, sizeof (tga_head));
|
||||
|
||||
head.image_type = 2;
|
||||
head.image_width = (unsigned short) w;
|
||||
head.image_height = (unsigned short) h;
|
||||
head.image_depth = (unsigned char) d;
|
||||
head.image_descriptor = (d == 32) ? 8 : 0;
|
||||
|
||||
if (d == 24 || d == 32)
|
||||
{
|
||||
if (FILE *stream = fopen(filename, "wb"))
|
||||
{
|
||||
if (fwrite(&head, sizeof (tga_head), 1, stream) == 1)
|
||||
{
|
||||
if (fwrite(p, d / 8, w * h, stream) == size_t(w * h))
|
||||
{
|
||||
fclose(stream);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fclose(stream);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Read a 24 or 32-bit uncompressed true-color Targa image file. Return a
|
||||
/// pointer to the raw pixels. Give width, height, and depth in w, h, d.
|
||||
/// Return null on failure.
|
||||
|
||||
inline void *read_tga(const char *filename, int& w, int& h, int& d)
|
||||
{
|
||||
tga_head head;
|
||||
|
||||
if (FILE *stream = fopen(filename, "rb"))
|
||||
{
|
||||
if (fread(&head, sizeof (tga_head), 1, stream) == 1)
|
||||
{
|
||||
if (head.image_type == 2)
|
||||
{
|
||||
w = int(head.image_width);
|
||||
h = int(head.image_height);
|
||||
d = int(head.image_depth);
|
||||
|
||||
if (fseek(stream, head.id_length, SEEK_CUR) == 0)
|
||||
{
|
||||
if (void *p = calloc(w * h, d / 8))
|
||||
{
|
||||
if (fread(p, d / 8, w * h, stream) == size_t(w * h))
|
||||
{
|
||||
fclose(stream);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(stream);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Load the named file into a newly-allocated buffer. Append nul.
|
||||
|
||||
inline char *read_shader_source(const char *filename)
|
||||
{
|
||||
FILE *stream = 0;
|
||||
void *p = 0;
|
||||
size_t n = 0;
|
||||
|
||||
if ((stream = fopen(filename, "rb")))
|
||||
{
|
||||
if (fseek(stream, 0, SEEK_END) == 0)
|
||||
{
|
||||
if ((n = (size_t) ftell(stream)))
|
||||
{
|
||||
if (fseek(stream, 0, SEEK_SET) == 0)
|
||||
{
|
||||
if ((p = calloc(n + 1, 1)))
|
||||
{
|
||||
fread(p, 1, n, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(stream);
|
||||
}
|
||||
else fprintf(stderr, "Failed to open '%s'.\n", filename);
|
||||
|
||||
return (char *) p;
|
||||
}
|
||||
|
||||
/// Check the shader compile status. If failed, print the log. Return status.
|
||||
|
||||
inline bool report_shader_status(GLuint shader, FILE *stream = stderr)
|
||||
{
|
||||
GLchar *p = 0;
|
||||
GLint s = 0;
|
||||
GLint n = 0;
|
||||
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &s);
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &n);
|
||||
|
||||
if (s == 0)
|
||||
{
|
||||
if ((p = (GLchar *) calloc(n + 1, 1)))
|
||||
{
|
||||
glGetShaderInfoLog(shader, n, NULL, p);
|
||||
|
||||
fprintf(stream, "Shader Error:\n%s", p);
|
||||
free(p);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Check the program link status. If failed, print the log. Return status.
|
||||
|
||||
inline bool report_program_status(GLuint program, FILE *stream = stderr)
|
||||
{
|
||||
GLchar *p = 0;
|
||||
GLint s = 0;
|
||||
GLint n = 0;
|
||||
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &s);
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &n);
|
||||
|
||||
if (s == 0)
|
||||
{
|
||||
if ((p = (GLchar *) calloc(n + 1, 1)))
|
||||
{
|
||||
glGetProgramInfoLog(program, n, NULL, p);
|
||||
|
||||
fprintf(stream, "Program Error:\n%s", p);
|
||||
free(p);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Compile and return a new shader of the given type using the given GLSL
|
||||
/// source string. Return 0 on failure.
|
||||
|
||||
inline GLuint init_shader(GLenum type, const char *source)
|
||||
{
|
||||
GLuint shader = glCreateShader(type);
|
||||
|
||||
if (shader)
|
||||
{
|
||||
glShaderSource (shader, 1, (const GLchar **) &source, NULL);
|
||||
glCompileShader(shader);
|
||||
|
||||
if (report_shader_status(shader))
|
||||
return shader;
|
||||
else
|
||||
glDeleteShader(shader);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Link and return a new program object with the given vertex and fragment
|
||||
/// shader objects. Return 0 on failure.
|
||||
|
||||
inline GLuint init_program(GLuint vert_shader, GLuint frag_shader)
|
||||
{
|
||||
GLuint program = glCreateProgram();
|
||||
|
||||
if (program)
|
||||
{
|
||||
glAttachShader(program, vert_shader);
|
||||
glAttachShader(program, frag_shader);
|
||||
|
||||
glLinkProgram(program);
|
||||
|
||||
if (report_program_status(program))
|
||||
return program;
|
||||
else
|
||||
glDeleteProgram(program);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Initialize and return an OpenGL program object using the named vertex
|
||||
/// and fragment shader source files. Return 0 on failure.
|
||||
|
||||
inline GLuint init_program(const char *vert_filename,
|
||||
const char *frag_filename)
|
||||
{
|
||||
GLuint program = 0;
|
||||
|
||||
char *vert_source = read_shader_source(vert_filename);
|
||||
char *frag_source = read_shader_source(frag_filename);
|
||||
|
||||
if (vert_source && frag_source)
|
||||
{
|
||||
GLuint vert_shader = init_shader(GL_VERTEX_SHADER, vert_source);
|
||||
GLuint frag_shader = init_shader(GL_FRAGMENT_SHADER, frag_source);
|
||||
|
||||
if (vert_shader && frag_shader)
|
||||
program = init_program(vert_shader, frag_shader);
|
||||
|
||||
glDeleteShader(frag_shader);
|
||||
glDeleteShader(vert_shader);
|
||||
}
|
||||
|
||||
free(frag_source);
|
||||
free(vert_source);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
#endif
|
15
etc/Makefile
Normal file
15
etc/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
OPTS= $(shell /usr/local/bin/sdl2-config --cflags) -I. -I.. -Wall
|
||||
LIBS= $(shell /usr/local/bin/sdl2-config --libs) -framework OpenGL
|
||||
|
||||
example : example.o ../obj.o
|
||||
c++ $(OPTS) -o $@ $^ $(LIBS)
|
||||
|
||||
%.o : %.cpp
|
||||
c++ $(OPTS) -o $@ -c $<
|
||||
|
||||
%.o : %.c
|
||||
cc $(OPTS) -o $@ -c $<
|
||||
|
||||
clean :
|
||||
rm example example.o ../obj.o
|
12
etc/README.md
Normal file
12
etc/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# OBJ Example
|
||||
|
||||
This example demonstrates the display of a model using the [OBJ C](https://github.com/rlk/obj) module.
|
||||
|
||||
- Left mouse button pans and tilts the camera
|
||||
- Right mouse button moves the light source
|
||||
- W A S D move the camera
|
||||
|
||||
This code conforms to the OpenGL 3.2 Core Profile and demonstrates diffuse, specular, and normal mapping. Normal map support is a non-standard extension to the MTL specification.
|
||||
|
||||
The example uses [SDL2](http://www.libsdl.org) for window management, with [GLFundamentals.hpp and GLDemonstration.hpp](https://github.com/rlk/GLFundamentals) for OpenGL state handling and interaction.
|
||||
|
72
etc/example.cpp
Normal file
72
etc/example.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include <GLFundamentals.hpp>
|
||||
#include <GLDemonstration.hpp>
|
||||
#include <obj.h>
|
||||
|
||||
class example : public gl::demonstration
|
||||
{
|
||||
obj *object;
|
||||
GLuint program;
|
||||
|
||||
GLint ProjectionMatrixLocation;
|
||||
GLint ModelViewMatrixLocation;
|
||||
GLint NormalMatrixLocation;
|
||||
GLint LightPositionLocation;
|
||||
GLint AmbientLightLocation;
|
||||
|
||||
public:
|
||||
|
||||
example();
|
||||
void draw();
|
||||
};
|
||||
|
||||
example::example() : gl::demonstration("OBJ Demo", 960, 540), object(0), program(0)
|
||||
{
|
||||
if ((program = gl::init_program("vertex.glsl", "fragment.glsl")))
|
||||
{
|
||||
glUseProgram(program);
|
||||
|
||||
ProjectionMatrixLocation = glGetUniformLocation(program, "ProjectionMatrix");
|
||||
ModelViewMatrixLocation = glGetUniformLocation(program, "ModelViewMatrix");
|
||||
NormalMatrixLocation = glGetUniformLocation(program, "NormalMatrix");
|
||||
LightPositionLocation = glGetUniformLocation(program, "LightPosition");
|
||||
AmbientLightLocation = glGetUniformLocation(program, "AmbientLight");
|
||||
|
||||
glUniform4f(AmbientLightLocation, 0.2, 0.2, 0.2, 1.0);
|
||||
|
||||
if ((object = obj_create("Chest.obj")))
|
||||
{
|
||||
obj_set_vert_loc(object, glGetAttribLocation(program, "vTangent"),
|
||||
glGetAttribLocation(program, "vNormal"),
|
||||
glGetAttribLocation(program, "vTexCoord"),
|
||||
glGetAttribLocation(program, "vPosition"));
|
||||
|
||||
obj_set_prop_loc(object, OBJ_KN, -1, glGetUniformLocation(program, "NormalTexture"), -1);
|
||||
obj_set_prop_loc(object, OBJ_KD, -1, glGetUniformLocation(program, "DiffuseTexture"), -1);
|
||||
obj_set_prop_loc(object, OBJ_KS, -1, glGetUniformLocation(program, "SpecularTexture"), -1);
|
||||
}
|
||||
}
|
||||
|
||||
glClearColor(0.2, 0.2, 0.2, 0.0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
cam_position = gl::vec3(0, 0, 3);
|
||||
}
|
||||
|
||||
void example::draw()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glUniformMatrix4fv(ProjectionMatrixLocation, 1, GL_TRUE, projection());
|
||||
glUniformMatrix4fv(ModelViewMatrixLocation, 1, GL_TRUE, view());
|
||||
glUniformMatrix3fv(NormalMatrixLocation, 1, GL_TRUE, normal(view()));
|
||||
glUniform4fv (LightPositionLocation, 1, light());
|
||||
|
||||
if (object) obj_render(object);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
example demo;
|
||||
demo.run();
|
||||
return 0;
|
||||
}
|
39
etc/fragment.glsl
Normal file
39
etc/fragment.glsl
Normal file
@ -0,0 +1,39 @@
|
||||
#version 150
|
||||
|
||||
uniform vec4 AmbientLight;
|
||||
|
||||
uniform sampler2D NormalTexture;
|
||||
uniform sampler2D DiffuseTexture;
|
||||
uniform sampler2D SpecularTexture;
|
||||
|
||||
in vec3 fView;
|
||||
in vec3 fLight;
|
||||
in vec2 fTexCoord;
|
||||
|
||||
out vec4 fColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Sample the textures.
|
||||
|
||||
vec4 tN = texture(NormalTexture, fTexCoord);
|
||||
vec4 tD = texture(DiffuseTexture, fTexCoord);
|
||||
vec4 tS = texture(SpecularTexture, fTexCoord);
|
||||
|
||||
// Determine the per-fragment lighting vectors.
|
||||
|
||||
vec3 N = normalize(2.0 * tN.xyz - 1.0);
|
||||
vec3 L = normalize(fLight);
|
||||
vec3 V = normalize(fView);
|
||||
vec3 R = reflect(L, N);
|
||||
|
||||
// Compute the diffuse shading.
|
||||
|
||||
float kd = max(dot(L, N), 0.0);
|
||||
float ks = pow(max(dot(V, R), 0.0), 8.0);
|
||||
|
||||
// Calculate the fragment color.
|
||||
|
||||
fColor.rgb = vec3(AmbientLight * tD + kd * tD + tS * ks);
|
||||
fColor.a = tD.a;
|
||||
}
|
32
etc/vertex.glsl
Normal file
32
etc/vertex.glsl
Normal file
@ -0,0 +1,32 @@
|
||||
#version 150
|
||||
|
||||
uniform mat4 ProjectionMatrix;
|
||||
uniform mat4 ModelViewMatrix;
|
||||
uniform mat3 NormalMatrix;
|
||||
uniform vec4 LightPosition;
|
||||
|
||||
in vec4 vPosition;
|
||||
in vec3 vNormal;
|
||||
in vec3 vTangent;
|
||||
in vec2 vTexCoord;
|
||||
|
||||
out vec3 fView;
|
||||
out vec3 fLight;
|
||||
out vec2 fTexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Tangent space vectors give the columns of the eye-to-tangent transform.
|
||||
|
||||
vec3 N = NormalMatrix * vNormal;
|
||||
vec3 T = NormalMatrix * vTangent;
|
||||
mat3 M = transpose(mat3(T, cross(N, T), N));
|
||||
|
||||
// Compute the per-fragment attributes.
|
||||
|
||||
fView = M * vec3(ModelViewMatrix * vPosition);
|
||||
fLight = M * vec3(ModelViewMatrix * LightPosition);
|
||||
fTexCoord = vTexCoord;
|
||||
|
||||
gl_Position = ProjectionMatrix * ModelViewMatrix * vPosition;
|
||||
}
|
133
obj.h
Normal file
133
obj.h
Normal file
@ -0,0 +1,133 @@
|
||||
/* Copyright (c) 2005 Robert Kooima */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining a */
|
||||
/* copy of this software and associated documentation files (the "Software"), */
|
||||
/* to deal in the Software without restriction, including without limitation */
|
||||
/* the rights to use, copy, modify, merge, publish, distribute, sublicense, */
|
||||
/* and/or sell copies of the Software, and to permit persons to whom the */
|
||||
/* Software is furnished to do so, subject to the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be included in */
|
||||
/* all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
|
||||
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */
|
||||
/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
|
||||
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
|
||||
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER */
|
||||
/* DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
#ifndef UTIL3D_OBJ_H
|
||||
#define UTIL3D_OBJ_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
enum {
|
||||
OBJ_KD,
|
||||
OBJ_KA,
|
||||
OBJ_KE,
|
||||
OBJ_KS,
|
||||
OBJ_NS,
|
||||
OBJ_KN,
|
||||
OBJ_PROP_COUNT
|
||||
};
|
||||
|
||||
#define OBJ_OPT_CLAMP 1
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
typedef struct obj obj;
|
||||
|
||||
obj *obj_create(const char *);
|
||||
void obj_render(obj *);
|
||||
void obj_delete(obj *);
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
int obj_add_mtrl(obj *);
|
||||
int obj_add_vert(obj *);
|
||||
int obj_add_poly(obj *, int);
|
||||
int obj_add_line(obj *, int);
|
||||
int obj_add_surf(obj *);
|
||||
|
||||
int obj_num_mtrl(const obj *);
|
||||
int obj_num_vert(const obj *);
|
||||
int obj_num_poly(const obj *, int);
|
||||
int obj_num_line(const obj *, int);
|
||||
int obj_num_surf(const obj *);
|
||||
|
||||
void obj_del_mtrl(obj *, int);
|
||||
void obj_del_vert(obj *, int);
|
||||
void obj_del_poly(obj *, int, int);
|
||||
void obj_del_line(obj *, int, int);
|
||||
void obj_del_surf(obj *, int);
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void obj_set_mtrl_name(obj *, int, const char *);
|
||||
void obj_set_mtrl_map (obj *, int, int, const char *);
|
||||
void obj_set_mtrl_opt (obj *, int, int, unsigned int);
|
||||
void obj_set_mtrl_c (obj *, int, int, const float *);
|
||||
void obj_set_mtrl_o (obj *, int, int, const float *);
|
||||
void obj_set_mtrl_s (obj *, int, int, const float *);
|
||||
|
||||
void obj_set_vert_v(obj *, int, const float *);
|
||||
void obj_set_vert_t(obj *, int, const float *);
|
||||
void obj_set_vert_n(obj *, int, const float *);
|
||||
void obj_set_vert_u(obj *, int, const float *);
|
||||
|
||||
void obj_set_poly(obj *, int, int, const int *);
|
||||
void obj_set_line(obj *, int, int, const int *);
|
||||
void obj_set_surf(obj *, int, int);
|
||||
|
||||
void obj_set_vert_loc(obj *, int, int, int, int);
|
||||
void obj_set_prop_loc(obj *, int, int, int, int);
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
const char *obj_get_mtrl_name(const obj *, int);
|
||||
unsigned int obj_get_mtrl_map (const obj *, int, int);
|
||||
unsigned int obj_get_mtrl_opt (const obj *, int, int);
|
||||
void obj_get_mtrl_c (const obj *, int, int, float *);
|
||||
void obj_get_mtrl_o (const obj *, int, int, float *);
|
||||
void obj_get_mtrl_s (const obj *, int, int, float *);
|
||||
|
||||
void obj_get_vert_v(const obj *, int, float *);
|
||||
void obj_get_vert_t(const obj *, int, float *);
|
||||
void obj_get_vert_n(const obj *, int, float *);
|
||||
|
||||
void obj_get_poly(const obj *, int, int, int *);
|
||||
void obj_get_line(const obj *, int, int, int *);
|
||||
int obj_get_surf(const obj *, int);
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void obj_render_mtrl(const obj *, int);
|
||||
void obj_render_surf(const obj *, int);
|
||||
void obj_render_file(const obj *);
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
unsigned int obj_load_image(const char *);
|
||||
|
||||
void obj_mini(obj *);
|
||||
void obj_norm(obj *);
|
||||
void obj_proc(obj *);
|
||||
void obj_uniq(obj *, float, float, int);
|
||||
void obj_sort(obj *, int);
|
||||
float obj_acmr(obj *, int);
|
||||
|
||||
void obj_bound(const obj *, float *);
|
||||
void obj_write(const obj *, const char *, const char *, int);
|
||||
|
||||
/*======================================================================+=====*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user