Last active
December 12, 2017 08:01
-
-
Save NotKyon/a4b9554fec955538bcde383d8e682409 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
*/ | |
/* | |
*/ //========================================// | |
/* // TILE - MINI-ENGINE (TEST) // Tile-1 | |
*/ // (C) Aaron J. Miller, 2012 // GPLv3 | |
/* //========================================// | |
*/ | |
/* | |
*/ //this software comes with absolutely no warranty// | |
//#include <GL/glfw.h> | |
#include <GLFW/glfw3.h> | |
#include <GL/gl.h> | |
//#include <GL/glext.h> | |
#include <math.h> | |
#include <errno.h> | |
#include <stdio.h> | |
#include <stdarg.h> | |
#include <stddef.h> | |
#include <stdlib.h> | |
#include <string.h> | |
/* | |
* ABOUT THE CODE QUALITY | |
* There is none. | |
* | |
* ... Enjoy! | |
* ~Aaron | |
* | |
* P.S.: Lack of code quality is due to this being a small test project. Ideas | |
* were implemented in a half-assed manner just to see if they worked. | |
*/ | |
/* | |
* ========================================================================== | |
* | |
* TYPEDEFS | |
* I Get It, Chevelle | |
* | |
* ========================================================================== | |
*/ | |
#define VECTOR_SIZE 16 | |
#define CACHELINE_SIZE 64 | |
#if 0 | |
# if _MSC_VER || __INTEL_COMPILER | |
# define VECTOR_ALIGNED __declspec(align(VECTOR_SIZE)) | |
# define CACHELINE_ALIGNED __declspec(align(CACHELINE_SIZE)) | |
# else | |
# define VECTOR_ALIGNED __attribute__((aligned(VECTOR_SIZE))) | |
# define CACHELINE_ALIGNED __attribute__((aligned(CACHELINE_SIZE))) | |
# endif | |
#else | |
# define VECTOR_ALIGNED | |
# define CACHELINE_ALIGNED | |
#endif | |
#if _MSC_VER || __INTEL_COMPILER | |
typedef signed __int64 sint64; | |
typedef unsigned __int64 uint64; | |
#else | |
# include <stdint.h> | |
typedef int64_t sint64; | |
typedef uint64_t uint64; | |
#endif | |
typedef unsigned int uint; | |
typedef signed char i8; | |
typedef signed short i16; | |
typedef signed int i32; | |
typedef sint64 i64; | |
typedef unsigned char u8; | |
typedef unsigned short u16; | |
typedef unsigned int u32; | |
typedef uint64 u64; | |
typedef unsigned int bool_t; | |
#undef TRUE | |
#undef FALSE | |
#define TRUE 1 | |
#define FALSE 0 | |
typedef void(*fn_t)(); | |
typedef union { fn_t fn; void *p; } fnptr_t; | |
#ifndef bitfield_t_defined | |
# define bitfield_t_defined 1 | |
typedef size_t bitfield_t; | |
#endif | |
struct entity_s; | |
typedef struct entity_s entity_t; | |
typedef void(*thinkfn_t)(entity_t *ent); | |
/* | |
* --------------- | |
* Renderer System | |
* --------------- | |
*/ | |
typedef struct CACHELINE_ALIGNED renderer_s { | |
/* | |
* FUNCTIONS | |
*/ | |
/* general */ | |
void(APIENTRY *ClearColor)(float r, float g, float b, float a); | |
void(APIENTRY *ClearDepth)(float z); | |
void(APIENTRY *ClearStencil)(unsigned int mask); | |
void(APIENTRY *Clear)(GLbitfield buffers); | |
/* shaders */ | |
GLuint(APIENTRY *CreateShader)(GLenum shaderType); | |
void(APIENTRY *ShaderSource)(GLuint shader, int numStrings, | |
const char **strings, int *stringLengths); | |
void(APIENTRY *CompileShader)(GLuint shader); | |
GLuint(APIENTRY *CreateProgram)(); | |
void(APIENTRY *AttachObject)(GLuint program, GLuint shader); | |
void(APIENTRY *LinkProgram)(GLuint program); | |
void(APIENTRY *UseProgram)(GLuint prog); | |
void(APIENTRY *GetShaderInfoLog)(GLuint shader, GLsizei bufSize, | |
GLsizei *length, char *infoLog); | |
void(APIENTRY *GetProgramInfoLog)(GLuint program, GLsizei bufSize, | |
GLsizei *length, char *infoLog); | |
void(APIENTRY *DeleteShader)(GLuint shader); | |
void(APIENTRY *DeleteProgram)(GLuint program); | |
/* | |
* VARIABLES | |
*/ | |
/* shaders */ | |
GLuint tileMap_frag; | |
GLuint tileMap_prog; | |
} renderer_t; | |
/* | |
* ------------------ | |
* Screen Description | |
* ------------------ | |
*/ | |
typedef struct glScreen_s { | |
int width; | |
int height; | |
int r, g, b, a; | |
int depth; | |
int stencil; | |
} glScreen_t; | |
/* | |
* ----- | |
* Brush | |
* ----- | |
* Brushes are used to define the appearance of a given Surface. | |
*/ | |
typedef enum { | |
kCM_None, | |
kCM_Front, | |
kCM_Back, | |
kCM_Both | |
} cullMode_t; | |
typedef enum { | |
kCF_Never, | |
kCF_Less, | |
kCF_LessEqual, | |
kCF_Equal, | |
kCF_NotEqual, | |
kCF_GreaterEqual, | |
kCF_Greater, | |
kCF_Always | |
} cmpFunc_t; | |
typedef struct CACHELINE_ALIGNED brush_s { | |
int refCnt; | |
struct { | |
GLuint vert, frag; | |
GLuint prog; | |
} shader; | |
struct { | |
float diffuse[4], ambient[4], emissive[4], specular[4]; | |
float shininess; | |
bool_t isLit:1; | |
bool_t useDiffuse:1; | |
bool_t useAmbient:1; | |
bool_t useEmissive:1; | |
bool_t useSpecular:1; | |
} lighting; | |
struct { | |
bool_t isVisible:1; | |
bool_t usesBinorm:1; | |
bool_t usesTangent:1; | |
/* | |
cullMode_t cullMode:2; | |
cmpFunc_t zCmpFunc:3; | |
*/ | |
unsigned cullMode:2; | |
unsigned zCmpFunc:3; | |
bool_t zTest:1; | |
bool_t zWrite:1; | |
bool_t zSort:1; | |
} drawing; | |
struct brush_s *prev, *next; | |
} brush_t; | |
extern brush_t *g_brush_head, *g_brush_tail; | |
/* | |
* ---- | |
* View | |
* ---- | |
* A view from which the scene is rendered. | |
*/ | |
typedef struct CACHELINE_ALIGNED view_s { | |
float M[16]; /*projection matrix*/ | |
union { | |
struct { | |
float fov; | |
} persp; | |
struct { | |
float left, top, right, bottom; | |
} ortho; | |
} proj; | |
bool_t isOrtho; | |
bool_t recalcProj; | |
float zn, zf; | |
struct { | |
float color[4]; | |
float depth; | |
unsigned char stencil; | |
bool_t clearColor:1; | |
bool_t clearDepth:1; | |
bool_t clearStencil:1; | |
} clear; | |
bool_t useAutoVP; | |
float vpAuto[4]; | |
int vpReal[4]; | |
/* | |
* TODO: Render targets can be handled here | |
*/ | |
struct entity_s *ent; | |
struct view_s *prev, *next; | |
} view_t; | |
extern view_t *g_view_head, *g_view_tail; | |
/* | |
* ----- | |
* Light | |
* ----- | |
*/ | |
typedef enum { | |
kLT_Point, | |
kLT_Dir, | |
kLT_Spot | |
} lightType_t; | |
typedef struct CACHELINE_ALIGNED light_s { | |
float xyz[3]; | |
float dir[3]; | |
float radius, intensity; | |
float innerCone, outerCone; | |
float color[4]; | |
struct entity_s *ent; | |
struct light_s *prev, *next; | |
} light_t; | |
extern light_t *g_light_head, *g_light_tail; | |
/* | |
* ------- | |
* Surface | |
* ------- | |
* Surfaces are rendered via Entities. They use brushes to define their | |
* appearance. | |
*/ | |
typedef struct vertex_s { | |
float xyz[3]; | |
float norm[3]; | |
float st[2]; | |
float binorm[3]; | |
float tangent[3]; | |
unsigned char color[4]; | |
} vertex_t; | |
typedef struct CACHELINE_ALIGNED surface_s { | |
unsigned short numVerts, maxVerts; | |
vertex_t *verts; | |
int numInds, maxInds; | |
unsigned short *inds; | |
int numPasses; | |
brush_t **passes; | |
struct entity_s *ent; | |
struct surface_s *s_prev, *s_next; | |
} surface_t; | |
/* | |
* ------ | |
* Entity | |
* ------ | |
* Represents an object. | |
*/ | |
struct CACHELINE_ALIGNED entity_s { | |
float l_model[16]; | |
float g_model[16]; | |
float MVP[16]; /*used by drawItem*/ | |
struct { | |
bool_t gModel:1; | |
} recalc; | |
thinkfn_t Think; | |
struct surface_s *s_head, *s_tail; | |
struct light_s *l_head, *l_tail; | |
struct view_s *view; | |
struct entity_s *prnt, **p_head, **p_tail; | |
struct entity_s *head, *tail; | |
struct entity_s *prev, *next; | |
}; | |
extern entity_t *g_ent_head, *g_ent_tail; | |
/* | |
* ------------ | |
* Render Queue | |
* ------------ | |
* The render queue performs the actual rendering commands | |
*/ | |
#pragma pack(push, 1) | |
typedef struct drawItem_s { | |
/* NOTE: 'order' should probably be unsigned */ | |
int order; /* ( RenderTarget<<24 ) | ( Pass<<16 ) | ( Order ) */ | |
float *M; | |
brush_t *brush; | |
surface_t *surf; | |
} drawItem_t; | |
#pragma pack(pop) | |
extern size_t g_numDrawItems, g_maxDrawItems; | |
extern drawItem_t *g_drawItems; | |
/* | |
* --------------- | |
* OpenGL Typedefs | |
* --------------- | |
*/ | |
#undef GL_FRAGMENT_SHADER_ARB | |
#undef GL_VERTEX_SHADER_ARB | |
#define GL_FRAGMENT_SHADER_ARB 0x8B30 | |
#define GL_VERTEX_SHADER_ARB 0x8B31 | |
#if 0 | |
/* GL_VERTEX_SHADER_ARB or GL_FRAGMENT_SHADER_ARB */ | |
GLuint(APIENTRY *gl_CreateShaderObject_ARB)(GLenum shaderType); | |
void(APIENTRY *gl_ShaderSource_ARB)(GLuint shader, int numStrings, | |
const char **strings, int *stringLengths); | |
void(APIENTRY *gl_CompileShader_ARB)(GLuint shader); | |
GLuint(APIENTRY *gl_CreateProgramObject_ARB)(); | |
void(APIENTRY *gl_AttachObject_ARB)(GLuint program, GLuint shader); | |
void(APIENTRY *gl_LinkProgram_ARB)(GLuint program); | |
void(APIENTRY *gl_UseProgramObject_ARB)(GLuint prog); | |
#endif | |
/* | |
* ========================================================================== | |
* | |
* API | |
* The Package, A Perfect Circle | |
* | |
* ========================================================================== | |
*/ | |
/* Assert */ | |
#if _MSC_VER||__INTEL_COMPILER | |
# define __func__ __FUNCTION__ | |
#endif | |
#ifndef BREAKPOINT | |
# if MK_ARCH_X86||MK_ARCH_X86_64 || __i386__||__x86_64__ || _M_IX86||_M_IX64 | |
# if __GNUC__ || __clang__ | |
# define BREAKPOINT() __asm__("int $3") | |
# else | |
# define BREAKPOINT() __asm int 3 | |
# endif | |
# elif __GNUC__ || __clang__ | |
# define BREAKPOINT() __builtin_trap() | |
# else | |
# error "Please provide a BREAKPOINT() macro for your platform." | |
# endif | |
#endif | |
#if DEBUG||_DEBUG||__debug__ || MK_DEBUG | |
# define ASSERT(x) if(!(x)){Error(__FILE__,__LINE__,__func__,\ | |
"ASSERT(%s) failed!", #x);BREAKPOINT();} | |
#else | |
# define ASSERT(x) /*do nothing!*/ | |
#endif | |
/* Report */ | |
#define TYPE_ERR "ERROR" | |
#define TYPE_WRN "WARNING" | |
void ReportV(const char *type, const char *file, int line, const char *func, | |
const char *message, va_list args); | |
void Report(const char *type, const char *file, int line, const char *func, | |
const char *message, ...); | |
void Warn(const char *file, int line, const char *func, const char *message, | |
...); | |
void Error(const char *file, int line, const char *func, const char *message, | |
...); | |
void WarnMessage(const char *message, ...); | |
void ErrorMessage(const char *message, ...); | |
void WarnFile(const char *file, int line, const char *message, ...); | |
void ErrorFile(const char *file, int line, const char *message, ...); | |
void ErrorFileExit(const char *file, int line, const char *message, ...); | |
void ErrorExit(const char *message, ...); | |
/* Memory */ | |
#define AllocStruct(x) ((x *)Memory((void *)0, sizeof(x))) | |
void *Alloc(size_t n); | |
void *AllocZero(size_t n); | |
void *Free(void *p); | |
void *Memory(void *p, size_t n); | |
char *DuplicateN(const char *src, size_t srcn); | |
char *Duplicate(const char *src); | |
char *CopyN(char *dst, const char *src, size_t srcn); | |
char *Copy(char *dst, const char *src); | |
char *AppendNChar(char *dst, const char *src, size_t srcn, char ch); | |
char *AppendN(char *dst, const char *src, size_t srcn); | |
char *Append(char *dst, const char *src); | |
char *TrimAppendChar(char *dst, const char *src, char ch); | |
char *TrimAppend(char *dst, const char *src); | |
char *StrCpy(char *dst, size_t dstn, const char *src); | |
char *StrCpyN(char *dst, size_t dstn, const char *src, size_t srcn); | |
char *StrCat(char *dst, size_t dstn, const char *src); | |
char *StrCatN(char *dst, size_t dstn, const char *src, size_t srcn); | |
/* Brush */ | |
brush_t *NewBrush(); | |
brush_t *CopyBrush(const brush_t *copyFrom); | |
brush_t *DeleteBrush(brush_t *brush); | |
void RetainBrush(brush_t *brush); | |
void SetBrushShader(brush_t *brush, const char *vertSrc, const char *fragSrc); | |
bool_t IsBrushVertexShaderAttached(const brush_t *brush); | |
bool_t IsBrushFragmentShaderAttached(const brush_t *brush); | |
bool_t IsBrushShaderAttached(const brush_t *brush); | |
void SetBrushDiffuse(brush_t *brush, float r, float g, float b, float a); | |
float GetBrushDiffuseR(const brush_t *brush); | |
float GetBrushDiffuseG(const brush_t *brush); | |
float GetBrushDiffuseB(const brush_t *brush); | |
float GetBrushDiffuseA(const brush_t *brush); | |
void SetBrushAmbient(brush_t *brush, float r, float g, float b, float a); | |
float GetBrushAmbientR(const brush_t *brush); | |
float GetBrushAmbientG(const brush_t *brush); | |
float GetBrushAmbientB(const brush_t *brush); | |
float GetBrushAmbientA(const brush_t *brush); | |
void SetBrushEmissive(brush_t *brush, float r, float g, float b, float a); | |
float GetBrushEmissiveR(const brush_t *brush); | |
float GetBrushEmissiveG(const brush_t *brush); | |
float GetBrushEmissiveB(const brush_t *brush); | |
float GetBrushEmissiveA(const brush_t *brush); | |
void SetBrushSpecular(brush_t *brush, float r, float g, float b, float a); | |
float GetBrushSpecularR(const brush_t *brush); | |
float GetBrushSpecularG(const brush_t *brush); | |
float GetBrushSpecularB(const brush_t *brush); | |
float GetBrushSpecularA(const brush_t *brush); | |
void SetBrushShininess(brush_t *brush, float shininess); | |
float GetBrushShininess(const brush_t *brush); | |
void EnableBrushLighting(brush_t *brush); | |
void DisableBrushLighting(brush_t *brush); | |
bool_t IsBrushLightingEnabled(const brush_t *brush); | |
void EnableBrushDiffuseLighting(brush_t *brush); | |
void DisableBrushDiffuseLighting(brush_t *brush); | |
bool_t IsBrushDiffuseLightingEnabled(const brush_t *brush); | |
void EnableBrushAmbientLighting(brush_t *brush); | |
void DisableBrushAmbientLighting(brush_t *brush); | |
bool_t IsBrushAmbientLightingEnabled(const brush_t *brush); | |
void EnableBrushEmissiveLighting(brush_t *brush); | |
void DisableBrushEmissiveLighting(brush_t *brush); | |
bool_t IsBrushEmissiveLightingEnabled(const brush_t *brush); | |
void EnableBrushSpecularLighting(brush_t *brush); | |
void DisableBrushSpecularLighting(brush_t *brush); | |
bool_t IsBrushSpecularLightingEnabled(const brush_t *brush); | |
void EnableBrushRendering(brush_t *brush); | |
void DisableBrushRendering(brush_t *brush); | |
bool_t IsBrushRenderingEnabled(const brush_t *brush); | |
void EnableBrushBinormal(brush_t *brush); | |
void DisableBrushBinormal(brush_t *brush); | |
bool_t IsBrushBinormalEnabled(const brush_t *brush); | |
void EnableBrushTangent(brush_t *brush); | |
void DisableBrushTangent(brush_t *brush); | |
bool_t IsBrushTangentEnabled(const brush_t *brush); | |
void SetBrushCullMode(brush_t *brush, cullMode_t cullMode); | |
cullMode_t GetBrushCullMode(const brush_t *brush); | |
void SetBrushZFunc(brush_t *brush, cmpFunc_t zCmpFunc); | |
cmpFunc_t GetBrushZFunc(const brush_t *brush); | |
void EnableBrushZTest(brush_t *brush); | |
void DisableBrushZTest(brush_t *brush); | |
bool_t IsBrushZTestEnabled(const brush_t *brush); | |
void EnableBrushZWrite(brush_t *brush); | |
void DisableBrushZWrite(brush_t *brush); | |
bool_t IsBrushZWriteEnabled(const brush_t *brush); | |
void EnableBrushZSort(brush_t *brush); | |
void DisableBrushZSort(brush_t *brush); | |
bool_t IsBrushZSortEnabled(const brush_t *brush); | |
brush_t *BrushBefore(const brush_t *brush); | |
brush_t *BrushAfter(const brush_t *brush); | |
brush_t *FirstBrush(); | |
brush_t *LastBrush(); | |
/* View */ | |
view_t *NewView(entity_t *ent); | |
view_t *DeleteView(view_t *v); | |
void DeleteAllViews(); | |
void SetViewMatrix(view_t *v, const float *M); | |
const float *GetViewMatrix(view_t *v); | |
void RecalcViewport(view_t *v, int w, int h); | |
void RecalcAllViewports(int w, int h); | |
int GetViewX(const view_t *v); | |
int GetViewY(const view_t *v); | |
int GetViewWidth(const view_t *v); | |
int GetViewHeight(const view_t *v); | |
void SetViewPerspective(view_t *v, float fov); | |
void SetViewOrtho(view_t *v, float left, float top, float right, float bottom); | |
void SetViewRange(view_t *v, float zn, float zf); | |
float GetViewPerspectiveFOV(const view_t *v); | |
float GetViewOrthoLeft(const view_t *v); | |
float GetViewOrthoTop(const view_t *v); | |
float GetViewOrthoRight(const view_t *v); | |
float GetViewOrthoBottom(const view_t *v); | |
float GetViewRangeNear(const view_t *v); | |
float GetViewRangeFar(const view_t *v); | |
void EnableViewClearColor(view_t *v); | |
void DisableViewClearColor(view_t *v); | |
bool_t IsViewClearColorEnabled(const view_t *v); | |
void EnableViewClearDepth(view_t *v); | |
void DisableViewClearDepth(view_t *v); | |
bool_t IsViewClearDepthEnabled(const view_t *v); | |
void EnableViewClearStencil(view_t *v); | |
void DisableViewClearStencil(view_t *v); | |
bool_t IsViewClearStencilEnabled(const view_t *v); | |
void SetViewClearColor(view_t *v, float r, float g, float b, float a); | |
float GetViewClearColorR(const view_t *v); | |
float GetViewClearColorG(const view_t *v); | |
float GetViewClearColorB(const view_t *v); | |
float GetViewClearColorA(const view_t *v); | |
void SetViewClearDepth(view_t *v, float z); | |
float GetViewClearDepth(const view_t *v); | |
void SetViewClearStencil(view_t *v, unsigned char mask); | |
unsigned char GetViewClearStencil(const view_t *v); | |
void SetViewAutoVP(view_t *vp, float l, float t, float r, float b); | |
void SetViewRealVP(view_t *vp, int l, int t, int r, int b); | |
view_t *ViewBefore(const view_t *v); | |
view_t *ViewAfter(const view_t *v); | |
view_t *FirstView(); | |
view_t *LastView(); | |
/* Surface */ | |
surface_t *NewSurface(entity_t *ent); | |
surface_t *DeleteSurface(surface_t *surf); | |
vertex_t *AddSurfaceVertices(surface_t *surf, unsigned short numVerts); | |
unsigned short *AddSurfaceTriangles(surface_t *surf, unsigned int numTris); | |
void AddSurfacePass(surface_t *surf, brush_t *brush); | |
surface_t *SurfaceBefore(const surface_t *surf); | |
surface_t *SurfaceAfter(const surface_t *surf); | |
surface_t *FirstSurface(const entity_t *ent); | |
surface_t *LastSurface(const entity_t *ent); | |
unsigned short GetSurfaceVertexCount(const surface_t *surf); | |
unsigned short GetSurfaceVertexCapacity(const surface_t *surf); | |
vertex_t *GetSurfaceVertex(const surface_t *surf, unsigned short i); | |
unsigned int GetSurfaceTriangleCount(const surface_t *surf); | |
unsigned int GetSurfaceTriangleCapacity(const surface_t *surf); | |
unsigned short *GetSurfaceTriangle(const surface_t *surf, unsigned int i); | |
unsigned int GetSurfacePassCount(const surface_t *surf); | |
brush_t *GetSurfacePass(const surface_t *surf, unsigned int i); | |
void SetVertexPosition(vertex_t *vert, float x, float y, float z); | |
void SetVertexNormal(vertex_t *vert, float x, float y, float z); | |
void SetVertexTexCoord(vertex_t *vert, float s, float t); | |
void SetVertexBinormal(vertex_t *vert, float x, float y, float z); | |
void SetVertexTangent(vertex_t *vert, float x, float y, float z); | |
float GetVertexPositionX(const vertex_t *vert); | |
float GetVertexPositionY(const vertex_t *vert); | |
float GetVertexPositionZ(const vertex_t *vert); | |
float GetVertexNormalX(const vertex_t *vert); | |
float GetVertexNormalY(const vertex_t *vert); | |
float GetVertexNormalZ(const vertex_t *vert); | |
float GetVertexTexCoordS(const vertex_t *vert); | |
float GetVertexTexCoordT(const vertex_t *vert); | |
float GetVertexBinormalX(const vertex_t *vert); | |
float GetVertexBinormalY(const vertex_t *vert); | |
float GetVertexBinormalZ(const vertex_t *vert); | |
float GetVertexTangentX(const vertex_t *vert); | |
float GetVertexTangentY(const vertex_t *vert); | |
float GetVertexTangentZ(const vertex_t *vert); | |
/* Math */ | |
float Degrees(float x); | |
float Radians(float x); | |
float Cos(float x); | |
float Sin(float x); | |
float Tan(float x); | |
float ACos(float x); | |
float ASin(float x); | |
float ATan(float x); | |
float ATan2(float y, float x); | |
float Sqrt(float x); | |
float InvSqrt(float x); | |
/* | |
MATRIX LAYOUT | |
------------- | |
M[ 0]=xx; M[ 4]=xy; M[ 8]=xz; M[12]=xw; | |
M[ 1]=yx; M[ 5]=yy; M[ 9]=yz; M[13]=yw; | |
M[ 2]=zx; M[ 6]=zy; M[10]=zz; M[14]=zw; | |
M[ 3]=wx; M[ 7]=wy; M[11]=wz; M[15]=ww; | |
M[12] = xw = translation x | |
M[13] = yw = translation y | |
M[14] = zw = translation z | |
*/ | |
void LoadIdentity(float *M); | |
void LoadPerspective(float *M, float fov, float aspect, float zn, float zf); | |
void LoadOrtho(float *M, float l, float r, float b, float t, float zn, | |
float zf); | |
void LoadTranslation(float *M, float x, float y, float z); | |
void LoadRotation(float *M, float x, float y, float z); | |
void LoadScaling(float *M, float x, float y, float z); | |
void ApplyTranslation(float *M, float x, float y, float z); | |
void ApplyXRotation(float *M, float x); | |
void ApplyYRotation(float *M, float y); | |
void ApplyZRotation(float *M, float z); | |
void ApplyRotation(float *M, float x, float y, float z); | |
void LoadAffineInverse(float *M, const float *P); | |
void AffineMultiply(float *M, const float *P, const float *Q); | |
void Multiply3(float *M, const float *P, const float *Q); | |
void Multiply4(float *M, const float *P, const float *Q); | |
/* Entity */ | |
entity_t *NewEntity(entity_t *prnt); | |
entity_t *DeleteEntity(entity_t *ent); | |
void DeleteAllEntities(); | |
void ResetEntityTransform(entity_t *ent); | |
void InvalidateEntityBranch(const entity_t *ent); | |
const float *GetEntityLocalMatrix(entity_t *ent); | |
const float *GetEntityGlobalMatrix(entity_t *ent); | |
void ProcessEntity(entity_t *ent); | |
void ProcessEntityChildren(const entity_t *ent); | |
void ProcessAllEntities(); | |
void SetEntityPosition(entity_t *ent, float x, float y, float z); | |
void SetEntityRotation(entity_t *ent, float x, float y, float z); | |
void MoveEntity(entity_t *ent, float x, float y, float z); | |
void MoveEntityX(entity_t *ent, float x); | |
void MoveEntityY(entity_t *ent, float y); | |
void MoveEntityZ(entity_t *ent, float z); | |
void TurnEntity(entity_t *ent, float x, float y, float z); | |
void TurnEntityX(entity_t *ent, float x); | |
void TurnEntityY(entity_t *ent, float y); | |
void TurnEntityZ(entity_t *ent, float z); | |
entity_t *FirstRootEntity(); | |
entity_t *LastRootEntity(); | |
entity_t *EntityParent(const entity_t *ent); | |
entity_t *FirstEntity(const entity_t *ent); | |
entity_t *LastEntity(const entity_t *ent); | |
entity_t *EntityBefore(const entity_t *ent); | |
entity_t *EntityAfter(const entity_t *ent); | |
/* Camera */ | |
entity_t *NewCamera(); | |
void SetCameraEntity(entity_t *cam); | |
entity_t *GetCameraEntity(); | |
void SetCameraPosition(float x, float y, float z); | |
void SetCameraRotation(float x, float y, float z); | |
void MoveCamera(float x, float y, float z); | |
void MoveCameraX(float x); | |
void MoveCameraY(float y); | |
void MoveCameraZ(float z); | |
void TurnCamera(float x, float y, float z); | |
void TurnCameraX(float x); | |
void TurnCameraY(float y); | |
void TurnCameraZ(float z); | |
int GetCameraViewX(); | |
int GetCameraViewY(); | |
int GetCameraViewWidth(); | |
int GetCameraViewHeight(); | |
void SetCameraPerspective(float fov); | |
void SetCameraOrtho(float left, float top, float right, float bottom); | |
void SetCameraRange(float zn, float zf); | |
float GetCameraPerspectiveFOV(); | |
float GetCameraOrthoLeft(); | |
float GetCameraOrthoTop(); | |
float GetCameraOrthoRight(); | |
float GetCameraOrthoBottom(); | |
float GetCameraRangeNear(); | |
float GetCameraRangeFar(); | |
void EnableCameraClearColor(); | |
void DisableCameraClearColor(); | |
bool_t IsCameraClearColorEnabled(); | |
void EnableCameraClearDepth(); | |
void DisableCameraClearDepth(); | |
bool_t IsCameraClearDepthEnabled(); | |
void EnableCameraClearStencil(); | |
void DisableCameraClearStencil(); | |
bool_t IsCameraClearStencilEnabled(); | |
void SetCameraClearColor(float r, float g, float b, float a); | |
float GetCameraClearColorR(); | |
float GetCameraClearColorG(); | |
float GetCameraClearColorB(); | |
float GetCameraClearColorA(); | |
void SetCameraClearDepth(float z); | |
float GetCameraClearDepth(); | |
void SetCameraClearStencil(unsigned char mask); | |
unsigned char GetCameraClearStencil(); | |
void SetCameraAutoVP(float l, float t, float r, float b); | |
void SetCameraRealVP(int l, int t, int r, int b); | |
/* Primitives */ | |
entity_t *NewTriangle(brush_t *brush); | |
/* Render Queue */ | |
drawItem_t *rq_AddDrawItems(size_t numItems); | |
void rq_AddEntities(entity_t *ent, view_t *v); | |
int rq_CmpFunc(const drawItem_t *a, const drawItem_t *b); | |
void rq_Sort(); | |
size_t rq_Count(); | |
size_t rq_Capacity(); | |
void rq_Draw(); | |
/* OpenGL */ | |
bool_t gl_IsExtensionSupported(const char *extension); | |
void gl_RequireExtension(const char *extension); | |
fn_t gl_Proc(const char *proc); | |
void gl_CheckError_(const char *file, int line); | |
#if defined(DEBUG)||defined(_DEBUG)||defined(__debug__) | |
# define gl_CheckError() gl_CheckError_(__FILE__,__LINE__) | |
#else | |
# define gl_CheckError() | |
#endif | |
/* Screen */ | |
void scr_Init(glScreen_t *desc); | |
void scr_Fini(); | |
bool_t scr_IsOpen(); | |
/* Renderer */ | |
extern renderer_t *R; | |
void r_Init(); | |
void r_Fini(); | |
void r_DrawView(view_t *view); | |
void r_Frame(double time); | |
/* | |
* ========================================================================== | |
* | |
* REPORT | |
* | |
* ========================================================================== | |
*/ | |
void ReportV(const char *type, const char *file, int line, const char *func, | |
const char *message, va_list args) { | |
int e; | |
e = errno; | |
fflush(stdout); | |
if (file) { | |
fprintf(stderr, "[%s", file); | |
if (line) | |
fprintf(stderr, "(%i)", line); | |
if (func) | |
fprintf(stderr, " %s", func); | |
fprintf(stderr, "] "); | |
} else if(func) | |
fprintf(stderr, "%s: ", func); | |
fprintf(stderr, "%s: ", type); | |
vfprintf(stderr, message, args); | |
if (e) { | |
#if _MSC_VER | |
char errbuf[4096]; | |
if (strerror_s(errbuf, sizeof(errbuf), e) != 0) | |
errbuf[0] = '\0'; | |
fprintf(stderr, ": %s (%i)", errbuf, e); | |
#else | |
fprintf(stderr, ": %s (%i)", strerror(e), e); | |
#endif | |
} | |
fprintf(stderr, "\n"); | |
fflush(stderr); | |
} | |
void Report(const char *type, const char *file, int line, const char *func, | |
const char *message, ...) { | |
va_list args; | |
va_start(args, message); | |
ReportV(type, file, line, func, message, args); | |
va_end(args); | |
} | |
void Warn(const char *file, int line, const char *func, const char *message, | |
...) { | |
va_list args; | |
va_start(args, message); | |
ReportV(TYPE_WRN, file, line, func, message, args); | |
va_end(args); | |
} | |
void Error(const char *file, int line, const char *func, const char *message, | |
...) { | |
va_list args; | |
va_start(args, message); | |
ReportV(TYPE_ERR, file, line, func, message, args); | |
va_end(args); | |
} | |
void WarnMessage(const char *message, ...) { | |
va_list args; | |
va_start(args, message); | |
ReportV(TYPE_WRN, (const char *)0, 0, (const char *)0, message, args); | |
va_end(args); | |
} | |
void ErrorMessage(const char *message, ...) { | |
va_list args; | |
va_start(args, message); | |
ReportV(TYPE_ERR, (const char *)0, 0, (const char *)0, message, args); | |
va_end(args); | |
} | |
void WarnFile(const char *file, int line, const char *message, ...) { | |
va_list args; | |
va_start(args, message); | |
ReportV(TYPE_WRN, file, line, (const char *)0, message, args); | |
va_end(args); | |
} | |
void ErrorFile(const char *file, int line, const char *message, ...) { | |
va_list args; | |
va_start(args, message); | |
ReportV(TYPE_ERR, file, line, (const char *)0, message, args); | |
va_end(args); | |
} | |
void ErrorFileExit(const char *file, int line, const char *message, ...) { | |
va_list args; | |
va_start(args, message); | |
ReportV(TYPE_ERR, file, line, (const char *)0, message, args); | |
va_end(args); | |
exit(EXIT_FAILURE); | |
} | |
void ErrorExit(const char *message, ...) { | |
va_list args; | |
va_start(args, message); | |
ReportV(TYPE_ERR, (const char *)0, 0, (const char *)0, message, args); | |
va_end(args); | |
exit(EXIT_FAILURE); | |
} | |
/* | |
* ========================================================================== | |
* | |
* MEMORY | |
* | |
* ========================================================================== | |
*/ | |
void *Alloc(size_t n) { | |
void *p; | |
if (!n) | |
return (void *)0; | |
p = malloc(n); | |
if (!p) { | |
BREAKPOINT(); | |
ErrorExit("Failed to allocate memory"); | |
} | |
return p; | |
} | |
void *AllocZero(size_t n) { | |
void *p; | |
p = Alloc(n); | |
if (!p) | |
return (void *)0; | |
memset(p, 0, n); | |
return p; | |
} | |
void *Free(void *p) { | |
if (!p) | |
return (void *)0; | |
free(p); | |
return (void *)0; | |
} | |
void *Memory(void *p, size_t n) { | |
void *q; | |
if (!p) | |
return Alloc(n); | |
if (!n) | |
return Free(p); | |
q = realloc(p, n); | |
if (!q) | |
ErrorExit("Failed to reallocate memory"); | |
return q; | |
} | |
char *DuplicateN(const char *src, size_t srcn) { | |
size_t l; | |
char *p; | |
if (!src) | |
return (char *)0; | |
l = srcn ? srcn : strlen(src); | |
p = (char *)Alloc(l + 1); | |
memcpy((void *)p, (const void *)src, l); | |
p[l] = 0; | |
return p; | |
} | |
char *Duplicate(const char *src) { | |
return DuplicateN(src, 0); | |
} | |
char *CopyN(char *dst, const char *src, size_t srcn) { | |
size_t len; | |
if (!src) | |
return (char *)Free((void *)dst); | |
len = srcn ? srcn : strlen(src); | |
dst = (char *)Memory((void *)dst, len + 1); | |
memcpy((void *)dst, (const char *)src, len); | |
dst[len] = 0; | |
return dst; | |
} | |
char *Copy(char *dst, const char *src) { | |
return CopyN(dst, src, 0); | |
} | |
char *AppendNChar(char *dst, const char *src, size_t srcn, char ch) { | |
size_t l1, l2, l3; | |
if (!dst) | |
return DuplicateN(src, srcn); | |
l1 = strlen(dst); | |
l2 = srcn ? srcn : strlen(src); | |
l3 = ch!='\0' ? 1 : 0; | |
dst = (char *)Memory((void *)dst, l1 + l2 + l3 + 1); | |
memcpy(&dst[l1], (const void *)src, l2); | |
dst[l1 + l2] = ch; | |
if (ch != '\0') | |
dst[l1 + l2 + l3] = '\0'; | |
return dst; | |
} | |
char *AppendN(char *dst, const char *src, size_t srcn) { | |
return AppendNChar(dst, src, srcn, '\0'); | |
} | |
char *Append(char *dst, const char *src) { | |
return AppendN(dst, src, 0); | |
} | |
char *TrimAppendChar(char *dst, const char *src, char ch) { | |
const char *p, *q; | |
for(p=src; *p<=' ' && *p!='\0'; p++); | |
q = strchr(p, '\0'); | |
while(q > p) { | |
if (*q++ > ' ') | |
break; | |
} | |
if (!(q - p)) | |
return dst; | |
return AppendNChar(dst, p, q - p, ch); | |
} | |
char *TrimAppend(char *dst, const char *src) { | |
return TrimAppendChar(dst, src, '\0'); | |
} | |
char *StrCpy(char *dst, size_t dstn, const char *src) { | |
return StrCpyN(dst, dstn, src, 0); | |
} | |
char *StrCpyN(char *dst, size_t dstn, const char *src, size_t srcn) { | |
size_t l; | |
char *r; | |
if (!dst) { | |
Error(__FILE__,__LINE__,__func__, "NULL destination string passed."); | |
return (char *)0; | |
} | |
if (!src) { | |
Error(__FILE__,__LINE__,__func__, "NULL source string passed."); | |
return (char *)0; | |
} | |
if (dstn < 2) { | |
Error(__FILE__,__LINE__,__func__, "No room in destination string."); | |
return (char *)0; | |
} | |
l = srcn ? srcn : strlen(src); | |
if (l + 1 > dstn) { | |
l = dstn - 1; | |
r = (char *)0; | |
Warn(__FILE__,__LINE__,__func__, "Overflow prevented."); | |
} else | |
r = dst; | |
if (l) | |
memcpy((void *)dst, (const void *)src, l); | |
dst[l] = 0; | |
return r; | |
} | |
char *StrCat(char *dst, size_t dstn, const char *src) { | |
return StrCatN(dst, dstn, src, 0); | |
} | |
char *StrCatN(char *dst, size_t dstn, const char *src, size_t srcn) { | |
char *p; | |
p = strchr(dst, '\0'); | |
p = StrCpyN(p, dstn - (p - dst), src, srcn); | |
if (p != (char *)0) | |
p = dst; | |
return p; | |
} | |
/* | |
* ========================================================================== | |
* | |
* BRUSH SYSTEM | |
* | |
* ========================================================================== | |
*/ | |
brush_t *g_brush_head = (brush_t *)0; | |
brush_t *g_brush_tail = (brush_t *)0; | |
brush_t *NewBrush() { | |
brush_t *brush; | |
brush = AllocStruct(brush_t); | |
brush->refCnt = 0; | |
brush->shader.vert = 0; | |
brush->shader.frag = 0; | |
brush->shader.prog = 0; | |
brush->lighting.diffuse[0] = 1.0f; | |
brush->lighting.diffuse[1] = 1.0f; | |
brush->lighting.diffuse[2] = 1.0f; | |
brush->lighting.diffuse[3] = 1.0f; | |
brush->lighting.ambient[0] = 0.0f; | |
brush->lighting.ambient[1] = 0.0f; | |
brush->lighting.ambient[2] = 0.0f; | |
brush->lighting.ambient[3] = 0.0f; | |
brush->lighting.emissive[0] = 0.0f; | |
brush->lighting.emissive[1] = 0.0f; | |
brush->lighting.emissive[2] = 0.0f; | |
brush->lighting.emissive[3] = 0.0f; | |
brush->lighting.specular[0] = 0.0f; | |
brush->lighting.specular[1] = 0.0f; | |
brush->lighting.specular[2] = 0.0f; | |
brush->lighting.specular[3] = 0.0f; | |
brush->lighting.shininess = 0.0f; | |
brush->lighting.isLit = TRUE; | |
brush->lighting.useDiffuse = TRUE; | |
brush->lighting.useAmbient = TRUE; | |
brush->lighting.useEmissive = TRUE; | |
brush->lighting.useSpecular = TRUE; | |
brush->drawing.isVisible = TRUE; | |
brush->drawing.usesBinorm = FALSE; | |
brush->drawing.usesTangent = FALSE; | |
brush->drawing.cullMode = kCM_Back; | |
brush->drawing.zCmpFunc = kCF_Greater; | |
brush->drawing.zTest = TRUE; | |
brush->drawing.zWrite = TRUE; | |
brush->drawing.zSort = FALSE; | |
brush->next = (brush_t *)0; | |
if ((brush->prev = g_brush_tail) != (brush_t *)0) | |
g_brush_tail->next = brush; | |
else | |
g_brush_head = brush; | |
g_brush_tail = brush; | |
return brush; | |
} | |
brush_t *CopyBrush(const brush_t *copyFrom) { | |
brush_t *brush; | |
brush = NewBrush(); | |
brush->shader.vert = 0; | |
brush->shader.frag = 0; | |
brush->shader.prog = 0; | |
brush->lighting.diffuse[0] = copyFrom->lighting.diffuse[0]; | |
brush->lighting.diffuse[1] = copyFrom->lighting.diffuse[1]; | |
brush->lighting.diffuse[2] = copyFrom->lighting.diffuse[2]; | |
brush->lighting.diffuse[3] = copyFrom->lighting.diffuse[3]; | |
brush->lighting.ambient[0] = copyFrom->lighting.ambient[0]; | |
brush->lighting.ambient[1] = copyFrom->lighting.ambient[1]; | |
brush->lighting.ambient[2] = copyFrom->lighting.ambient[2]; | |
brush->lighting.ambient[3] = copyFrom->lighting.ambient[3]; | |
brush->lighting.emissive[0] = copyFrom->lighting.emissive[0]; | |
brush->lighting.emissive[1] = copyFrom->lighting.emissive[1]; | |
brush->lighting.emissive[2] = copyFrom->lighting.emissive[2]; | |
brush->lighting.emissive[3] = copyFrom->lighting.emissive[3]; | |
brush->lighting.specular[0] = copyFrom->lighting.specular[0]; | |
brush->lighting.specular[1] = copyFrom->lighting.specular[1]; | |
brush->lighting.specular[2] = copyFrom->lighting.specular[2]; | |
brush->lighting.specular[3] = copyFrom->lighting.specular[3]; | |
brush->lighting.shininess = copyFrom->lighting.shininess; | |
brush->lighting.isLit = copyFrom->lighting.isLit; | |
brush->lighting.useDiffuse = copyFrom->lighting.useDiffuse; | |
brush->lighting.useAmbient = copyFrom->lighting.useAmbient; | |
brush->lighting.useEmissive = copyFrom->lighting.useEmissive; | |
brush->lighting.useSpecular = copyFrom->lighting.useSpecular; | |
brush->drawing.isVisible = copyFrom->drawing.isVisible; | |
brush->drawing.usesBinorm = copyFrom->drawing.usesBinorm; | |
brush->drawing.usesTangent = copyFrom->drawing.usesTangent; | |
brush->drawing.cullMode = copyFrom->drawing.cullMode; | |
brush->drawing.zCmpFunc = copyFrom->drawing.zCmpFunc; | |
brush->drawing.zTest = copyFrom->drawing.zTest; | |
brush->drawing.zWrite = copyFrom->drawing.zWrite; | |
brush->drawing.zSort = copyFrom->drawing.zSort; | |
return brush; | |
} | |
brush_t *DeleteBrush(brush_t *brush) { | |
if (!brush) | |
return (brush_t *)0; | |
if (--brush->refCnt > 0) | |
return (brush_t *)0; | |
if (brush->shader.prog) { | |
R->DeleteProgram(brush->shader.prog); | |
brush->shader.prog = 0; | |
} | |
if (brush->shader.frag) { | |
R->DeleteShader(brush->shader.frag); | |
brush->shader.frag = 0; | |
} | |
if (brush->shader.vert) { | |
R->DeleteShader(brush->shader.vert); | |
brush->shader.vert = 0; | |
} | |
if (brush->prev) | |
brush->prev->next = brush->next; | |
if (brush->next) | |
brush->next->prev = brush->prev; | |
if (g_brush_head==brush) | |
g_brush_head = brush->next; | |
if (g_brush_tail==brush) | |
g_brush_tail = brush->prev; | |
return (brush_t *)Memory((void *)brush, 0); | |
} | |
void RetainBrush(brush_t *brush) { | |
brush->refCnt++; | |
} | |
void SetBrushShader(brush_t *brush, const char *vertSrc, const char *fragSrc) { | |
char infoLog[8192]; | |
if (brush->shader.prog) { | |
R->DeleteProgram(brush->shader.prog); | |
brush->shader.prog = 0; | |
} | |
if (brush->shader.frag) { | |
R->DeleteShader(brush->shader.frag); | |
brush->shader.frag = 0; | |
} | |
if (brush->shader.vert) { | |
R->DeleteShader(brush->shader.vert); | |
brush->shader.vert = 0; | |
} | |
if (vertSrc) brush->shader.vert = R->CreateShader(GL_VERTEX_SHADER_ARB); | |
if (fragSrc) brush->shader.frag = R->CreateShader(GL_FRAGMENT_SHADER_ARB); | |
if (!vertSrc && !fragSrc) | |
return; | |
/* | |
* TODO: Better error reporting... | |
*/ | |
brush->shader.prog = R->CreateProgram(); | |
if (vertSrc) { | |
R->ShaderSource(brush->shader.vert, 1, &vertSrc, (int *)0); | |
R->CompileShader(brush->shader.vert); | |
R->GetShaderInfoLog(brush->shader.vert, sizeof(infoLog), 0, infoLog); | |
fprintf(stderr, "%s\n", infoLog); | |
R->AttachObject(brush->shader.prog, brush->shader.vert); | |
} | |
if (fragSrc) { | |
R->ShaderSource(brush->shader.frag, 1, &fragSrc, (int *)0); | |
R->CompileShader(brush->shader.frag); | |
R->GetShaderInfoLog(brush->shader.frag, sizeof(infoLog), 0, infoLog); | |
fprintf(stderr, "%s\n", infoLog); | |
R->AttachObject(brush->shader.prog, brush->shader.frag); | |
} | |
R->LinkProgram(brush->shader.prog); | |
R->GetProgramInfoLog(brush->shader.prog, sizeof(infoLog), 0, infoLog); | |
fprintf(stderr, "%s\n", infoLog); | |
} | |
bool_t IsBrushVertexShaderAttached(const brush_t *brush) { | |
return brush->shader.vert ? TRUE : FALSE; | |
} | |
bool_t IsBrushFragmentShaderAttached(const brush_t *brush) { | |
return brush->shader.frag ? TRUE : FALSE; | |
} | |
bool_t IsBrushShaderAttached(const brush_t *brush) { | |
return brush->shader.prog ? TRUE : FALSE; | |
} | |
void SetBrushDiffuse(brush_t *brush, float r, float g, float b, float a) { | |
brush->lighting.diffuse[0] = r; | |
brush->lighting.diffuse[1] = g; | |
brush->lighting.diffuse[2] = b; | |
brush->lighting.diffuse[3] = a; | |
} | |
float GetBrushDiffuseR(const brush_t *brush) { | |
return brush->lighting.diffuse[0]; | |
} | |
float GetBrushDiffuseG(const brush_t *brush) { | |
return brush->lighting.diffuse[1]; | |
} | |
float GetBrushDiffuseB(const brush_t *brush) { | |
return brush->lighting.diffuse[2]; | |
} | |
float GetBrushDiffuseA(const brush_t *brush) { | |
return brush->lighting.diffuse[3]; | |
} | |
void SetBrushAmbient(brush_t *brush, float r, float g, float b, float a) { | |
brush->lighting.ambient[0] = r; | |
brush->lighting.ambient[1] = g; | |
brush->lighting.ambient[2] = b; | |
brush->lighting.ambient[3] = a; | |
} | |
float GetBrushAmbientR(const brush_t *brush) { | |
return brush->lighting.ambient[0]; | |
} | |
float GetBrushAmbientG(const brush_t *brush) { | |
return brush->lighting.ambient[1]; | |
} | |
float GetBrushAmbientB(const brush_t *brush) { | |
return brush->lighting.ambient[2]; | |
} | |
float GetBrushAmbientA(const brush_t *brush) { | |
return brush->lighting.ambient[3]; | |
} | |
void SetBrushEmissive(brush_t *brush, float r, float g, float b, float a) { | |
brush->lighting.emissive[0] = r; | |
brush->lighting.emissive[1] = g; | |
brush->lighting.emissive[2] = b; | |
brush->lighting.emissive[3] = a; | |
} | |
float GetBrushEmissiveR(const brush_t *brush) { | |
return brush->lighting.emissive[0]; | |
} | |
float GetBrushEmissiveG(const brush_t *brush) { | |
return brush->lighting.emissive[1]; | |
} | |
float GetBrushEmissiveB(const brush_t *brush) { | |
return brush->lighting.emissive[2]; | |
} | |
float GetBrushEmissiveA(const brush_t *brush) { | |
return brush->lighting.emissive[3]; | |
} | |
void SetBrushSpecular(brush_t *brush, float r, float g, float b, float a) { | |
brush->lighting.specular[0] = r; | |
brush->lighting.specular[1] = g; | |
brush->lighting.specular[2] = b; | |
brush->lighting.specular[3] = a; | |
} | |
float GetBrushSpecularR(const brush_t *brush) { | |
return brush->lighting.specular[0]; | |
} | |
float GetBrushSpecularG(const brush_t *brush) { | |
return brush->lighting.specular[1]; | |
} | |
float GetBrushSpecularB(const brush_t *brush) { | |
return brush->lighting.specular[2]; | |
} | |
float GetBrushSpecularA(const brush_t *brush) { | |
return brush->lighting.specular[3]; | |
} | |
void SetBrushShininess(brush_t *brush, float shininess) { | |
brush->lighting.shininess = shininess; | |
} | |
float GetBrushShininess(const brush_t *brush) { | |
return brush->lighting.shininess; | |
} | |
void EnableBrushLighting(brush_t *brush) { | |
brush->lighting.isLit = TRUE; | |
} | |
void DisableBrushLighting(brush_t *brush) { | |
brush->lighting.isLit = FALSE; | |
} | |
bool_t IsBrushLightingEnabled(const brush_t *brush) { | |
return brush->lighting.isLit; | |
} | |
void EnableBrushDiffuseLighting(brush_t *brush) { | |
brush->lighting.useDiffuse = TRUE; | |
} | |
void DisableBrushDiffuseLighting(brush_t *brush) { | |
brush->lighting.useDiffuse = FALSE; | |
} | |
bool_t IsBrushDiffuseLightingEnabled(const brush_t *brush) { | |
return brush->lighting.useDiffuse; | |
} | |
void EnableBrushAmbientLighting(brush_t *brush) { | |
brush->lighting.useAmbient = TRUE; | |
} | |
void DisableBrushAmbientLighting(brush_t *brush) { | |
brush->lighting.useAmbient = FALSE; | |
} | |
bool_t IsBrushAmbientLightingEnabled(const brush_t *brush) { | |
return brush->lighting.useAmbient; | |
} | |
void EnableBrushEmissiveLighting(brush_t *brush) { | |
brush->lighting.useEmissive = TRUE; | |
} | |
void DisableBrushEmissiveLighting(brush_t *brush) { | |
brush->lighting.useEmissive = FALSE; | |
} | |
bool_t IsBrushEmissiveLightingEnabled(const brush_t *brush) { | |
return brush->lighting.useEmissive; | |
} | |
void EnableBrushSpecularLighting(brush_t *brush) { | |
brush->lighting.useSpecular = TRUE; | |
} | |
void DisableBrushSpecularLighting(brush_t *brush) { | |
brush->lighting.useSpecular = FALSE; | |
} | |
bool_t IsBrushSpecularLightingEnabled(const brush_t *brush) { | |
return brush->lighting.useSpecular; | |
} | |
void EnableBrushRendering(brush_t *brush) { | |
brush->drawing.isVisible = TRUE; | |
} | |
void DisableBrushRendering(brush_t *brush) { | |
brush->drawing.isVisible = FALSE; | |
} | |
bool_t IsBrushRenderingEnabled(const brush_t *brush) { | |
return brush->drawing.isVisible; | |
} | |
void EnableBrushBinormal(brush_t *brush) { | |
brush->drawing.usesBinorm = TRUE; | |
} | |
void DisableBrushBinormal(brush_t *brush) { | |
brush->drawing.usesBinorm = FALSE; | |
} | |
bool_t IsBrushBinormalEnabled(const brush_t *brush) { | |
return brush->drawing.usesBinorm; | |
} | |
void EnableBrushTangent(brush_t *brush) { | |
brush->drawing.usesTangent = TRUE; | |
} | |
void DisableBrushTangent(brush_t *brush) { | |
brush->drawing.usesTangent = FALSE; | |
} | |
bool_t IsBrushTangentEnabled(const brush_t *brush) { | |
return brush->drawing.usesTangent; | |
} | |
void SetBrushCullMode(brush_t *brush, cullMode_t cullMode) { | |
brush->drawing.cullMode = cullMode; | |
} | |
cullMode_t GetBrushCullMode(const brush_t *brush) { | |
return brush->drawing.cullMode; | |
} | |
void SetBrushZFunc(brush_t *brush, cmpFunc_t zCmpFunc) { | |
brush->drawing.zCmpFunc = zCmpFunc; | |
} | |
cmpFunc_t GetBrushZFunc(const brush_t *brush) { | |
return brush->drawing.zCmpFunc; | |
} | |
void EnableBrushZTest(brush_t *brush) { | |
brush->drawing.zTest = TRUE; | |
} | |
void DisableBrushZTest(brush_t *brush) { | |
brush->drawing.zTest = FALSE; | |
} | |
bool_t IsBrushZTestEnabled(const brush_t *brush) { | |
return brush->drawing.zTest; | |
} | |
void EnableBrushZWrite(brush_t *brush) { | |
brush->drawing.zWrite = TRUE; | |
} | |
void DisableBrushZWrite(brush_t *brush) { | |
brush->drawing.zWrite = FALSE; | |
} | |
bool_t IsBrushZWriteEnabled(const brush_t *brush) { | |
return brush->drawing.zWrite; | |
} | |
void EnableBrushZSort(brush_t *brush) { | |
brush->drawing.zSort = TRUE; | |
} | |
void DisableBrushZSort(brush_t *brush) { | |
brush->drawing.zSort = FALSE; | |
} | |
bool_t IsBrushZSortEnabled(const brush_t *brush) { | |
return brush->drawing.zSort; | |
} | |
brush_t *BrushBefore(const brush_t *brush) { | |
return brush->prev; | |
} | |
brush_t *BrushAfter(const brush_t *brush) { | |
return brush->next; | |
} | |
brush_t *FirstBrush() { | |
return g_brush_head; | |
} | |
brush_t *LastBrush() { | |
return g_brush_tail; | |
} | |
/* | |
* ========================================================================== | |
* | |
* VIEW SYSTEM | |
* | |
* ========================================================================== | |
*/ | |
view_t *g_view_head = (view_t *)0; | |
view_t *g_view_tail = (view_t *)0; | |
view_t *NewView(entity_t *ent) { | |
view_t *v; | |
v = AllocStruct(view_t); | |
v->proj.persp.fov = 60.0f; | |
v->recalcProj = TRUE; | |
v->isOrtho = FALSE; | |
v->zn = 1.0f; | |
v->zf = 4096.0f; | |
v->clear.color[0] = 0.1f; | |
v->clear.color[1] = 0.3f; | |
v->clear.color[2] = 0.5f; | |
v->clear.color[3] = 1.0f; | |
v->clear.depth = 0.0f; | |
v->clear.stencil = 0x00; | |
v->clear.clearColor = TRUE; | |
v->clear.clearDepth = TRUE; | |
v->clear.clearStencil = TRUE; | |
v->useAutoVP = TRUE; | |
v->vpAuto[0] = 0.0f; | |
v->vpAuto[1] = 0.0f; | |
v->vpAuto[2] = 1.0f; | |
v->vpAuto[3] = 1.0f; | |
v->vpReal[0] = 0; | |
v->vpReal[1] = 0; | |
v->vpReal[2] = 0; | |
v->vpReal[3] = 0; | |
if (ent->view) | |
ent->view->ent = (entity_t *)0; | |
v->ent = ent; | |
ent->view = v; | |
v->next = (view_t *)0; | |
if ((v->prev = g_view_tail) != (view_t *)0) | |
g_view_tail->next = v; | |
else | |
g_view_head = v; | |
g_view_tail = v; | |
return v; | |
} | |
view_t *DeleteView(view_t *v) { | |
if (!v) | |
return (view_t *)0; | |
if (v->ent) | |
v->ent->view = (view_t *)0; | |
if (v->prev) | |
v->prev->next = v->next; | |
if (v->next) | |
v->next->prev = v->prev; | |
if (g_view_head==v) | |
g_view_head = v->next; | |
if (g_view_tail==v) | |
g_view_tail = v->prev; | |
return (view_t *)Memory((void *)v, 0); | |
} | |
void DeleteAllViews() { | |
while(g_view_head) | |
DeleteView(g_view_head); | |
} | |
void SetViewMatrix(view_t *v, const float *M) { | |
memcpy(&v->M[0], &M[0], sizeof(v->M)); | |
v->recalcProj = FALSE; | |
} | |
const float *GetViewMatrix(view_t *v) { | |
float l, r, b, t; | |
float w, h; | |
if (!v->recalcProj) | |
return v->M; | |
if (v->isOrtho) { | |
l = v->proj.ortho.left; | |
r = v->proj.ortho.right; | |
b = v->proj.ortho.bottom; | |
t = v->proj.ortho.top; | |
LoadOrtho(v->M, l, r, b, t, v->zn, v->zf); | |
} else { | |
w = (float)GetViewWidth(v); | |
h = (float)GetViewHeight(v); | |
LoadPerspective(v->M, v->proj.persp.fov, w/h, v->zn, v->zf); | |
} | |
v->recalcProj = FALSE; | |
return v->M; | |
} | |
void RecalcViewport(view_t *v, int w, int h) { | |
if (!v->useAutoVP) | |
return; | |
v->vpReal[0] = (int)(v->vpAuto[0]*(float)w); | |
v->vpReal[1] = (int)(v->vpAuto[1]*(float)h); | |
v->vpReal[2] = (int)(v->vpAuto[2]*(float)w); | |
v->vpReal[3] = (int)(v->vpAuto[3]*(float)h); | |
} | |
void RecalcAllViewports(int w, int h) { | |
view_t *v; | |
for(v=g_view_head; v; v=v->next) | |
RecalcViewport(v, w, h); | |
} | |
int GetViewX(const view_t *v) { | |
return v->vpReal[0]; | |
} | |
int GetViewY(const view_t *v) { | |
return v->vpReal[1]; | |
} | |
int GetViewWidth(const view_t *v) { | |
return v->vpReal[2] - v->vpReal[0]; | |
} | |
int GetViewHeight(const view_t *v) { | |
return v->vpReal[3] - v->vpReal[1]; | |
} | |
void SetViewPerspective(view_t *v, float fov) { | |
v->proj.persp.fov = fov; | |
v->isOrtho = FALSE; | |
v->recalcProj = TRUE; | |
} | |
void SetViewOrtho(view_t *v, float left, float top, float right, float bottom) { | |
v->proj.ortho.left = left; | |
v->proj.ortho.top = top; | |
v->proj.ortho.right = right; | |
v->proj.ortho.bottom = bottom; | |
v->isOrtho = TRUE; | |
v->recalcProj = TRUE; | |
} | |
void SetViewRange(view_t *v, float zn, float zf) { | |
v->zn = zn; | |
v->zf = zf; | |
v->recalcProj = TRUE; | |
} | |
float GetViewPerspectiveFOV(const view_t *v) { | |
return v->proj.persp.fov; | |
} | |
float GetViewOrthoLeft(const view_t *v) { | |
return v->proj.ortho.left; | |
} | |
float GetViewOrthoTop(const view_t *v) { | |
return v->proj.ortho.top; | |
} | |
float GetViewOrthoRight(const view_t *v) { | |
return v->proj.ortho.right; | |
} | |
float GetViewOrthoBottom(const view_t *v) { | |
return v->proj.ortho.bottom; | |
} | |
float GetViewRangeNear(const view_t *v) { | |
return v->zn; | |
} | |
float GetViewRangeFar(const view_t *v) { | |
return v->zf; | |
} | |
void EnableViewClearColor(view_t *v) { | |
v->clear.clearColor = TRUE; | |
} | |
void DisableViewClearColor(view_t *v) { | |
v->clear.clearColor = FALSE; | |
} | |
bool_t IsViewClearColorEnabled(const view_t *v) { | |
return v->clear.clearColor; | |
} | |
void EnableViewClearDepth(view_t *v) { | |
v->clear.clearDepth = TRUE; | |
} | |
void DisableViewClearDepth(view_t *v) { | |
v->clear.clearDepth = FALSE; | |
} | |
bool_t IsViewClearDepthEnabled(const view_t *v) { | |
return v->clear.clearDepth; | |
} | |
void EnableViewClearStencil(view_t *v) { | |
v->clear.clearStencil = TRUE; | |
} | |
void DisableViewClearStencil(view_t *v) { | |
v->clear.clearStencil = FALSE; | |
} | |
bool_t IsViewClearStencilEnabled(const view_t *v) { | |
return v->clear.clearStencil; | |
} | |
void SetViewClearColor(view_t *v, float r, float g, float b, float a) { | |
v->clear.color[0] = r; | |
v->clear.color[1] = g; | |
v->clear.color[2] = b; | |
v->clear.color[3] = a; | |
} | |
float GetViewClearColorR(const view_t *v) { | |
return v->clear.color[0]; | |
} | |
float GetViewClearColorG(const view_t *v) { | |
return v->clear.color[1]; | |
} | |
float GetViewClearColorB(const view_t *v) { | |
return v->clear.color[2]; | |
} | |
float GetViewClearColorA(const view_t *v) { | |
return v->clear.color[3]; | |
} | |
void SetViewClearDepth(view_t *v, float z) { | |
v->clear.depth = z; | |
} | |
float GetViewClearDepth(const view_t *v) { | |
return v->clear.depth; | |
} | |
void SetViewClearStencil(view_t *v, unsigned char mask) { | |
v->clear.stencil = mask; | |
} | |
unsigned char GetViewClearStencil(const view_t *v) { | |
return v->clear.stencil; | |
} | |
void SetViewAutoVP(view_t *v, float l, float t, float r, float b) { | |
v->useAutoVP = TRUE; | |
v->vpAuto[0] = l; | |
v->vpAuto[1] = t; | |
v->vpAuto[2] = r; | |
v->vpAuto[3] = b; | |
} | |
void SetViewRealVP(view_t *v, int l, int t, int r, int b) { | |
v->useAutoVP = FALSE; | |
v->vpReal[0] = l; | |
v->vpReal[1] = t; | |
v->vpReal[2] = r; | |
v->vpReal[3] = b; | |
} | |
view_t *ViewBefore(const view_t *v) { | |
return v->prev; | |
} | |
view_t *ViewAfter(const view_t *v) { | |
return v->next; | |
} | |
view_t *FirstView() { | |
return g_view_head; | |
} | |
view_t *LastView() { | |
return g_view_tail; | |
} | |
/* | |
* ========================================================================== | |
* | |
* SURFACE FUNCTIONS | |
* | |
* ========================================================================== | |
*/ | |
surface_t *NewSurface(entity_t *ent) { | |
surface_t *surf; | |
surf = AllocStruct(surface_t); | |
surf->numVerts = 0; | |
surf->maxVerts = 0; | |
surf->verts = (vertex_t *)0; | |
surf->numInds = 0; | |
surf->maxInds = 0; | |
surf->inds = (unsigned short *)0; | |
surf->numPasses = 0; | |
surf->passes = (brush_t **)0; | |
surf->ent = ent; | |
surf->s_next = (surface_t *)0; | |
if ((surf->s_prev = ent->s_tail) != (surface_t *)0) | |
ent->s_tail->s_next = surf; | |
else | |
ent->s_head = surf; | |
ent->s_tail = surf; | |
return surf; | |
} | |
surface_t *DeleteSurface(surface_t *surf) { | |
int i; | |
if (!surf) | |
return (surface_t *)0; | |
surf->verts = (vertex_t *)Memory((void *)surf->verts, 0); | |
surf->inds = (unsigned short *)Memory((void *)surf->inds, 0); | |
for(i=0; i<surf->numPasses; i++) | |
DeleteBrush(surf->passes[i]); | |
surf->passes = (brush_t **)Memory((void *)surf->passes, 0); | |
if (surf->s_prev) | |
surf->s_prev->s_next = surf->s_next; | |
if (surf->s_next) | |
surf->s_next->s_prev = surf->s_prev; | |
if (surf->ent->s_head==surf) | |
surf->ent->s_head = surf->s_next; | |
if (surf->ent->s_tail==surf) | |
surf->ent->s_tail = surf->s_prev; | |
return (surface_t *)Memory((void *)surf, 0); | |
} | |
vertex_t *AddSurfaceVertices(surface_t *surf, unsigned short numVerts) { | |
#define VERT_GRAN 8 | |
size_t n; | |
if (surf->numVerts + numVerts > surf->maxVerts) { | |
surf->maxVerts = surf->numVerts + numVerts; | |
surf->maxVerts -= surf->maxVerts%VERT_GRAN; | |
surf->maxVerts += VERT_GRAN; | |
n = surf->maxVerts*sizeof(vertex_t); | |
surf->verts = (vertex_t *)Memory((void *)surf->verts, n); | |
} | |
n = surf->numVerts; | |
surf->numVerts += numVerts; | |
return &surf->verts[n]; | |
#undef VERT_GRAN | |
} | |
unsigned short *AddSurfaceTriangles(surface_t *surf, unsigned int numTris) { | |
#define IND_GRAN 16 | |
size_t n; | |
int numInds; | |
numInds = numTris*3; | |
if (surf->numInds + numInds > surf->maxInds) { | |
surf->maxInds = surf->numInds + numInds; | |
surf->maxInds -= surf->numInds%IND_GRAN; | |
surf->maxInds += IND_GRAN; | |
n = surf->maxInds*sizeof(unsigned short); | |
surf->inds = (unsigned short *)Memory((void *)surf->inds, n); | |
} | |
n = surf->numInds; | |
surf->numInds += numInds; | |
return &surf->inds[n]; | |
#undef IND_GRAN | |
} | |
void AddSurfacePass(surface_t *surf, brush_t *brush) { | |
size_t n; | |
n = (surf->numPasses + 1)*sizeof(brush_t *); | |
surf->passes = (brush_t **)Memory((void *)surf->passes, n); | |
surf->passes[surf->numPasses++] = brush; | |
brush->refCnt++; | |
} | |
surface_t *SurfaceBefore(const surface_t *surf) { | |
return surf->s_prev; | |
} | |
surface_t *SurfaceAfter(const surface_t *surf) { | |
return surf->s_next; | |
} | |
surface_t *FirstSurface(const entity_t *ent) { | |
return ent->s_head; | |
} | |
surface_t *LastSurface(const entity_t *ent) { | |
return ent->s_tail; | |
} | |
unsigned short GetSurfaceVertexCount(const surface_t *surf) { | |
return surf->numVerts; | |
} | |
unsigned short GetSurfaceVertexCapacity(const surface_t *surf) { | |
return surf->maxVerts; | |
} | |
vertex_t *GetSurfaceVertex(const surface_t *surf, unsigned short i) { | |
return &surf->verts[i]; | |
} | |
unsigned int GetSurfaceTriangleCount(const surface_t *surf) { | |
return surf->numInds*3; | |
} | |
unsigned int GetSurfaceTriangleCapacity(const surface_t *surf) { | |
return surf->maxInds*3; | |
} | |
unsigned short *GetSurfaceTriangle(const surface_t *surf, unsigned int i) { | |
return &surf->inds[i*3]; | |
} | |
unsigned int GetSurfacePassCount(const surface_t *surf) { | |
return surf->numPasses; | |
} | |
brush_t *GetSurfacePass(const surface_t *surf, unsigned int i) { | |
return surf->passes[i]; | |
} | |
void SetVertexPosition(vertex_t *vert, float x, float y, float z) { | |
vert->xyz[0] = x; | |
vert->xyz[1] = y; | |
vert->xyz[2] = z; | |
} | |
void SetVertexNormal(vertex_t *vert, float x, float y, float z) { | |
vert->norm[0] = x; | |
vert->norm[1] = y; | |
vert->norm[2] = z; | |
} | |
void SetVertexTexCoord(vertex_t *vert, float s, float t) { | |
vert->st[0] = s; | |
vert->st[1] = t; | |
} | |
void SetVertexBinormal(vertex_t *vert, float x, float y, float z) { | |
vert->binorm[0] = x; | |
vert->binorm[1] = y; | |
vert->binorm[2] = z; | |
} | |
void SetVertexTangent(vertex_t *vert, float x, float y, float z) { | |
vert->tangent[0] = x; | |
vert->tangent[1] = y; | |
vert->tangent[2] = z; | |
} | |
float GetVertexPositionX(const vertex_t *vert) { | |
return vert->xyz[0]; | |
} | |
float GetVertexPositionY(const vertex_t *vert) { | |
return vert->xyz[1]; | |
} | |
float GetVertexPositionZ(const vertex_t *vert) { | |
return vert->xyz[2]; | |
} | |
float GetVertexNormalX(const vertex_t *vert) { | |
return vert->norm[0]; | |
} | |
float GetVertexNormalY(const vertex_t *vert) { | |
return vert->norm[1]; | |
} | |
float GetVertexNormalZ(const vertex_t *vert) { | |
return vert->norm[2]; | |
} | |
float GetVertexTexCoordS(const vertex_t *vert) { | |
return vert->st[0]; | |
} | |
float GetVertexTexCoordT(const vertex_t *vert) { | |
return vert->st[1]; | |
} | |
float GetVertexBinormalX(const vertex_t *vert) { | |
return vert->binorm[0]; | |
} | |
float GetVertexBinormalY(const vertex_t *vert) { | |
return vert->binorm[1]; | |
} | |
float GetVertexBinormalZ(const vertex_t *vert) { | |
return vert->binorm[2]; | |
} | |
float GetVertexTangentX(const vertex_t *vert) { | |
return vert->tangent[0]; | |
} | |
float GetVertexTangentY(const vertex_t *vert) { | |
return vert->tangent[1]; | |
} | |
float GetVertexTangentZ(const vertex_t *vert) { | |
return vert->tangent[2]; | |
} | |
/* | |
* ========================================================================== | |
* | |
* MATH | |
* | |
* ========================================================================== | |
*/ | |
float Degrees(float x) { return x/3.1415926535f*180.0f; } | |
float Radians(float x) { return x/180.0f*3.1415926535f; } | |
float Cos(float x) { return cosf(Radians(x)); } | |
float Sin(float x) { return sinf(Radians(x)); } | |
float Tan(float x) { return tanf(Radians(x)); } | |
float ACos(float x) { return Degrees(acosf(x)); } | |
float ASin(float x) { return Degrees(asinf(x)); } | |
float ATan(float x) { return Degrees(atanf(x)); } | |
float ATan2(float y, float x) { return Degrees(atan2f(y, x)); } | |
float Sqrt(float x) { return sqrtf(x); } | |
float InvSqrt(float x) { return 1.0f/sqrtf(x); } | |
/* | |
M[ 0]=xx; M[ 4]=xy; M[ 8]=xz; M[12]=xw; | |
M[ 1]=yx; M[ 5]=yy; M[ 9]=yz; M[13]=yw; | |
M[ 2]=zx; M[ 6]=zy; M[10]=zz; M[14]=zw; | |
M[ 3]=wx; M[ 7]=wy; M[11]=wz; M[15]=ww; | |
*/ | |
void LoadIdentity(float *M) { | |
M[ 0]=1; M[ 4]=0; M[ 8]=0; M[12]=0; | |
M[ 1]=0; M[ 5]=1; M[ 9]=0; M[13]=0; | |
M[ 2]=0; M[ 6]=0; M[10]=1; M[14]=0; | |
M[ 3]=0; M[ 7]=0; M[11]=0; M[15]=1; | |
} | |
void LoadPerspective(float *M, float fov, float aspect, float zn, float zf) { | |
float a, b, c, d; | |
b = 1.0f/Tan(0.5f*fov); | |
a = b/aspect; | |
c = zf/(zf - zn); | |
d = -zn*zf/(zf - zn); | |
M[ 0]=a; M[ 4]=0; M[ 8]=0; M[12]=0; | |
M[ 1]=0; M[ 5]=b; M[ 9]=0; M[13]=0; | |
M[ 2]=0; M[ 6]=0; M[10]=c; M[14]=d; | |
M[ 3]=0; M[ 7]=0; M[11]=1; M[15]=0; | |
} | |
void LoadOrtho(float *M, float l, float r, float b, float t, float zn, | |
float zf) { | |
float A, B, C, D, E, F; | |
A = 2.0f/(r - l); | |
B = (l + r)/(l - r); | |
C = 2.0f/(t - b); | |
D = (t + b)/(b - t); | |
E = 1.0f/(zf - zn); | |
F = zn/(zn - zf); | |
M[ 0]=A; M[ 4]=0; M[ 8]=0; M[12]=B; | |
M[ 1]=0; M[ 5]=C; M[ 9]=0; M[13]=D; | |
M[ 2]=0; M[ 6]=0; M[10]=E; M[14]=F; | |
M[ 3]=0; M[ 7]=0; M[11]=0; M[15]=1; | |
} | |
void LoadTranslation(float *M, float x, float y, float z) { | |
M[ 0]=1; M[ 4]=0; M[ 8]=0; M[12]=x; | |
M[ 1]=0; M[ 5]=1; M[ 9]=0; M[13]=y; | |
M[ 2]=0; M[ 6]=0; M[10]=1; M[14]=z; | |
M[ 3]=0; M[ 7]=0; M[11]=0; M[15]=1; | |
} | |
void LoadRotation(float *M, float x, float y, float z) { | |
float sx,sy,sz, cx,cy,cz; | |
float cz_nsx; | |
sx=Sin(x); sy=Sin(y); sz=Sin(z); | |
cx=Cos(x); cy=Cos(y); cz=Cos(z); | |
cz_nsx = cz*-sx; | |
M[ 0]= cz*cy; M[ 4]=-sz*cx; M[ 8]= cz*-sy + (sz*sx)*cy; | |
M[ 1]= sz*cy + cz_nsx*sy; M[ 5]= cz*cx; M[ 9]= sz*-sy + cz_nsx*cy; | |
M[ 2]= cx*sy; M[ 6]= sx; M[10]= cx*cy; | |
M[12]=0; | |
M[13]=0; | |
M[14]=0; | |
M[ 3]=0; M[ 7]=0; M[11]=0; M[15]=1; | |
} | |
void LoadScaling(float *M, float x, float y, float z) { | |
M[ 0]=x; M[ 4]=0; M[ 8]=0; M[12]=0; | |
M[ 1]=0; M[ 5]=y; M[ 9]=0; M[13]=0; | |
M[ 2]=0; M[ 6]=0; M[10]=z; M[14]=0; | |
M[ 3]=0; M[ 7]=0; M[11]=0; M[15]=1; | |
} | |
void ApplyTranslation(float *M, float x, float y, float z) { | |
M[12] += M[ 0]*x + M[ 4]*y + M[ 8]*z; | |
M[13] += M[ 1]*x + M[ 5]*y + M[ 9]*z; | |
M[14] += M[ 2]*x + M[ 6]*y + M[10]*z; | |
} | |
void ApplyXRotation(float *M, float x) { | |
float c, s, t; | |
c = Cos(x); | |
s = Sin(x); | |
t = M[ 4]; | |
M[ 4] = t*c + M[ 8]*s; | |
M[ 8] = t*-s + M[ 8]*c; | |
t = M[ 5]; | |
M[ 5] = t*c + M[ 9]*s; | |
M[ 9] = t*-s + M[ 9]*c; | |
t = M[ 6]; | |
M[ 6] = t*c + M[10]*s; | |
M[10] = t*-s + M[10]*c; | |
} | |
void ApplyYRotation(float *M, float y) { | |
float c, s, t; | |
c = Cos(y); | |
s = Sin(y); | |
t = M[ 0]; | |
M[ 0] = t*c + M[ 8]*s; | |
M[ 8] = t*-s + M[ 8]*c; | |
t = M[ 1]; | |
M[ 1] = t*c + M[ 9]*s; | |
M[ 9] = t*-s + M[ 9]*c; | |
t = M[ 2]; | |
M[ 2] = t*c + M[10]*s; | |
M[10] = t*-s + M[10]*c; | |
} | |
void ApplyZRotation(float *M, float z) { | |
float c, s, t; | |
c = Cos(z); | |
s = Sin(z); | |
t = M[ 0]; | |
M[ 0] = t*c + M[ 4]*s; | |
M[ 4] = t*-s + M[ 4]*c; | |
t = M[ 1]; | |
M[ 1] = t*c + M[ 5]*s; | |
M[ 5] = t*-s + M[ 5]*c; | |
t = M[ 2]; | |
M[ 2] = t*c + M[ 6]*s; | |
M[ 6] = t*-s + M[ 6]*c; | |
} | |
void ApplyRotation(float *M, float x, float y, float z) { | |
ApplyZRotation(M, z); | |
ApplyXRotation(M, x); | |
ApplyYRotation(M, y); | |
} | |
void LoadAffineInverse(float *M, const float *P) { | |
float x, y, z; | |
x = -(P[12]*P[ 0] + P[13]*P[ 1] + P[14]*P[ 2]); | |
y = -(P[12]*P[ 4] + P[13]*P[ 5] + P[14]*P[ 6]); | |
z = -(P[12]*P[ 8] + P[13]*P[ 9] + P[14]*P[10]); | |
M[ 0]=P[ 0]; M[ 4]=P[ 1]; M[ 8]=P[ 2]; M[12]=x; | |
M[ 1]=P[ 4]; M[ 5]=P[ 5]; M[ 9]=P[ 6]; M[13]=y; | |
M[ 2]=P[ 8]; M[ 6]=P[ 9]; M[10]=P[10]; M[14]=z; | |
M[ 3]= 0 ; M[ 7]= 0 ; M[11]= 0 ; M[15]=1; | |
} | |
void AffineMultiply(float *M, const float *P, const float *Q) { | |
M[ 0]=P[ 0]*Q[ 0] + P[ 4]*Q[ 1] + P[ 8]*Q[ 2]; | |
M[ 4]=P[ 0]*Q[ 4] + P[ 4]*Q[ 5] + P[ 8]*Q[ 6]; | |
M[ 8]=P[ 0]*Q[ 8] + P[ 4]*Q[ 9] + P[ 8]*Q[10]; | |
M[12]=P[ 0]*Q[12] + P[ 4]*Q[13] + P[ 8]*Q[14] + P[12]; | |
M[ 1]=P[ 1]*Q[ 0] + P[ 5]*Q[ 1] + P[ 9]*Q[ 2]; | |
M[ 5]=P[ 1]*Q[ 4] + P[ 5]*Q[ 5] + P[ 9]*Q[ 6]; | |
M[ 9]=P[ 1]*Q[ 8] + P[ 5]*Q[ 9] + P[ 9]*Q[10]; | |
M[13]=P[ 1]*Q[12] + P[ 5]*Q[13] + P[ 9]*Q[14] + P[13]; | |
M[ 2]=P[ 2]*Q[ 0] + P[ 6]*Q[ 1] + P[10]*Q[ 2]; | |
M[ 6]=P[ 2]*Q[ 4] + P[ 6]*Q[ 5] + P[10]*Q[ 6]; | |
M[10]=P[ 2]*Q[ 8] + P[ 6]*Q[ 9] + P[10]*Q[10]; | |
M[14]=P[ 2]*Q[12] + P[ 6]*Q[13] + P[10]*Q[14] + P[14]; | |
M[ 3]=0; | |
M[ 7]=0; | |
M[11]=0; | |
M[15]=1; | |
} | |
void Multiply3(float *M, const float *P, const float *Q) { | |
M[ 0]=P[ 0]*Q[ 0] + P[ 4]*Q[ 1] + P[ 8]*Q[ 2]; | |
M[ 4]=P[ 0]*Q[ 4] + P[ 4]*Q[ 5] + P[ 8]*Q[ 6]; | |
M[ 8]=P[ 0]*Q[ 8] + P[ 4]*Q[ 9] + P[ 8]*Q[10]; | |
M[12]=0; | |
M[ 1]=P[ 1]*Q[ 0] + P[ 5]*Q[ 1] + P[ 9]*Q[ 2]; | |
M[ 5]=P[ 1]*Q[ 4] + P[ 5]*Q[ 5] + P[ 9]*Q[ 6]; | |
M[ 9]=P[ 1]*Q[ 8] + P[ 5]*Q[ 9] + P[ 9]*Q[10]; | |
M[13]=0; | |
M[ 2]=P[ 2]*Q[ 0] + P[ 6]*Q[ 1] + P[10]*Q[ 2]; | |
M[ 6]=P[ 2]*Q[ 4] + P[ 6]*Q[ 5] + P[10]*Q[ 6]; | |
M[10]=P[ 2]*Q[ 8] + P[ 6]*Q[ 9] + P[10]*Q[10]; | |
M[14]=0; | |
M[ 3]=0; | |
M[ 7]=0; | |
M[11]=0; | |
M[15]=1; | |
} | |
void Multiply4(float *M, const float *P, const float *Q) { | |
M[ 0]=P[ 0]*Q[ 0] + P[ 4]*Q[ 1] + P[ 8]*Q[ 2] + P[12]*Q[ 3]; | |
M[ 4]=P[ 0]*Q[ 4] + P[ 4]*Q[ 5] + P[ 8]*Q[ 6] + P[12]*Q[ 7]; | |
M[ 8]=P[ 0]*Q[ 8] + P[ 4]*Q[ 9] + P[ 8]*Q[10] + P[12]*Q[11]; | |
M[12]=P[ 0]*Q[12] + P[ 4]*Q[13] + P[ 8]*Q[14] + P[12]*Q[15]; | |
M[ 1]=P[ 1]*Q[ 0] + P[ 5]*Q[ 1] + P[ 9]*Q[ 2] + P[13]*Q[ 3]; | |
M[ 5]=P[ 1]*Q[ 4] + P[ 5]*Q[ 5] + P[ 9]*Q[ 6] + P[13]*Q[ 7]; | |
M[ 9]=P[ 1]*Q[ 8] + P[ 5]*Q[ 9] + P[ 9]*Q[10] + P[13]*Q[11]; | |
M[13]=P[ 1]*Q[12] + P[ 5]*Q[13] + P[ 9]*Q[14] + P[13]*Q[15]; | |
M[ 2]=P[ 2]*Q[ 0] + P[ 6]*Q[ 1] + P[10]*Q[ 2] + P[14]*Q[ 3]; | |
M[ 6]=P[ 2]*Q[ 4] + P[ 6]*Q[ 5] + P[10]*Q[ 6] + P[14]*Q[ 7]; | |
M[10]=P[ 2]*Q[ 8] + P[ 6]*Q[ 9] + P[10]*Q[10] + P[14]*Q[11]; | |
M[14]=P[ 2]*Q[12] + P[ 6]*Q[13] + P[10]*Q[14] + P[14]*Q[15]; | |
M[ 3]=P[ 3]*Q[ 0] + P[ 7]*Q[ 1] + P[11]*Q[ 2] + P[15]*Q[ 3]; | |
M[ 7]=P[ 3]*Q[ 4] + P[ 7]*Q[ 5] + P[11]*Q[ 6] + P[15]*Q[ 7]; | |
M[11]=P[ 3]*Q[ 8] + P[ 7]*Q[ 9] + P[11]*Q[10] + P[15]*Q[11]; | |
M[15]=P[ 3]*Q[12] + P[ 7]*Q[13] + P[11]*Q[14] + P[15]*Q[15]; | |
} | |
/* | |
* ========================================================================== | |
* | |
* ENTITY | |
* | |
* ========================================================================== | |
*/ | |
entity_t *g_ent_head = (entity_t *)0; | |
entity_t *g_ent_tail = (entity_t *)0; | |
entity_t *NewEntity(entity_t *prnt) { | |
entity_t *ent; | |
ent = AllocStruct(entity_t); | |
LoadIdentity(ent->l_model); | |
LoadIdentity(ent->g_model); | |
LoadIdentity(ent->MVP); | |
ent->recalc.gModel = prnt ? TRUE : FALSE; | |
ent->Think = (thinkfn_t)0; | |
ent->s_head = (surface_t *)0; | |
ent->s_tail = (surface_t *)0; | |
ent->l_head = (light_t *)0; | |
ent->l_tail = (light_t *)0; | |
ent->view = (view_t *)0; | |
ent->prnt = prnt; | |
ent->p_head = prnt ? &prnt->head : &g_ent_head; | |
ent->p_tail = prnt ? &prnt->tail : &g_ent_tail; | |
ent->head = (entity_t *)0; | |
ent->tail = (entity_t *)0; | |
ent->next = (entity_t *)0; | |
if ((ent->prev = *ent->p_tail) != (entity_t *)0) | |
(*ent->p_tail)->next = ent; | |
else | |
*ent->p_head = ent; | |
*ent->p_tail = ent; | |
return ent; | |
} | |
entity_t *DeleteEntity(entity_t *ent) { | |
if (!ent) | |
return (entity_t *)0; | |
while(ent->head) | |
DeleteEntity(ent->head); | |
while(ent->s_head) | |
DeleteSurface(ent->s_head); | |
if (ent->prev) | |
ent->prev->next = ent->next; | |
if (ent->next) | |
ent->next->prev = ent->prev; | |
if (*ent->p_head==ent) | |
*ent->p_head = ent->next; | |
if (*ent->p_tail==ent) | |
*ent->p_tail = ent->prev; | |
return (entity_t *)Memory((void *)ent, 0); | |
} | |
void DeleteAllEntities() { | |
while(g_ent_head) | |
DeleteEntity(g_ent_head); | |
} | |
void ResetEntityTransform(entity_t *ent) { | |
LoadIdentity(ent->l_model); | |
ent->recalc.gModel = TRUE; | |
} | |
void InvalidateEntityBranch(const entity_t *ent) { | |
entity_t *chld; | |
for(chld=ent->head; chld; chld=chld->next) { | |
chld->recalc.gModel = TRUE; | |
InvalidateEntityBranch(chld); | |
} | |
} | |
const float *GetEntityLocalMatrix(entity_t *ent) { | |
return ent->l_model; | |
} | |
const float *GetEntityGlobalMatrix(entity_t *ent) { | |
entity_t *prnt; | |
prnt = ent->prnt; | |
if (!prnt) | |
return ent->l_model; | |
if (!ent->recalc.gModel) | |
return ent->g_model; | |
AffineMultiply(ent->g_model, GetEntityGlobalMatrix(prnt), ent->l_model); | |
ent->recalc.gModel = FALSE; | |
InvalidateEntityBranch(ent); | |
return ent->g_model; | |
} | |
void ProcessEntity(entity_t *ent) { | |
if (ent->Think) | |
ent->Think(ent); | |
} | |
void ProcessEntityChildren(const entity_t *ent) { | |
entity_t *chld; | |
for(chld=ent->head; chld; chld=chld->next) { | |
ProcessEntity(chld); | |
ProcessEntityChildren(chld); | |
} | |
} | |
void ProcessAllEntities() { | |
entity_t *ent; | |
for(ent=g_ent_head; ent; ent=ent->next) { | |
ProcessEntity(ent); | |
ProcessEntityChildren(ent); | |
} | |
} | |
void SetEntityPosition(entity_t *ent, float x, float y, float z) { | |
ent->l_model[12] = x; | |
ent->l_model[13] = y; | |
ent->l_model[14] = z; | |
ent->recalc.gModel = TRUE; | |
} | |
void SetEntityRotation(entity_t *ent, float x, float y, float z) { | |
float xyz[3]; | |
xyz[0] = ent->l_model[12]; | |
xyz[1] = ent->l_model[13]; | |
xyz[2] = ent->l_model[14]; | |
LoadRotation(ent->l_model, x, y, z); | |
ent->l_model[12] = xyz[0]; | |
ent->l_model[13] = xyz[1]; | |
ent->l_model[14] = xyz[2]; | |
ent->recalc.gModel = TRUE; | |
} | |
void MoveEntity(entity_t *ent, float x, float y, float z) { | |
ApplyTranslation(ent->l_model, x, y, z); | |
ent->recalc.gModel = TRUE; | |
} | |
void MoveEntityX(entity_t *ent, float x) { | |
MoveEntity(ent, x, 0, 0); | |
} | |
void MoveEntityY(entity_t *ent, float y) { | |
MoveEntity(ent, 0, y, 0); | |
} | |
void MoveEntityZ(entity_t *ent, float z) { | |
MoveEntity(ent, 0, 0, z); | |
} | |
void TurnEntity(entity_t *ent, float x, float y, float z) { | |
ApplyRotation(ent->l_model, x, y, z); | |
ent->recalc.gModel = TRUE; | |
} | |
void TurnEntityX(entity_t *ent, float x) { | |
ApplyXRotation(ent->l_model, x); | |
ent->recalc.gModel = TRUE; | |
} | |
void TurnEntityY(entity_t *ent, float y) { | |
ApplyYRotation(ent->l_model, y); | |
ent->recalc.gModel = TRUE; | |
} | |
void TurnEntityZ(entity_t *ent, float z) { | |
ApplyZRotation(ent->l_model, z); | |
ent->recalc.gModel = TRUE; | |
} | |
entity_t *FirstRootEntity() { | |
return g_ent_head; | |
} | |
entity_t *LastRootEntity() { | |
return g_ent_tail; | |
} | |
entity_t *EntityParent(const entity_t *ent) { | |
return ent->prnt; | |
} | |
entity_t *FirstEntity(const entity_t *ent) { | |
return ent->head; | |
} | |
entity_t *LastEntity(const entity_t *ent) { | |
return ent->tail; | |
} | |
entity_t *EntityBefore(const entity_t *ent) { | |
return ent->prev; | |
} | |
entity_t *EntityAfter(const entity_t *ent) { | |
return ent->next; | |
} | |
/* | |
* ========================================================================== | |
* | |
* CAMERA SYSTEM | |
* | |
* ========================================================================== | |
*/ | |
entity_t *g_camera = (entity_t *)0; | |
entity_t *NewCamera() { | |
entity_t *cam; | |
cam = NewEntity((entity_t *)0); | |
NewView(cam); | |
if (!g_camera) | |
g_camera = cam; | |
return cam; | |
} | |
void SetCameraEntity(entity_t *cam) { | |
if (!cam || !cam->view) | |
return; | |
g_camera = cam; | |
} | |
entity_t *GetCameraEntity() { | |
return g_camera; | |
} | |
void SetCameraPosition(float x, float y, float z) { | |
SetEntityPosition(g_camera, x, y, z); | |
} | |
void SetCameraRotation(float x, float y, float z) { | |
SetEntityRotation(g_camera, x, y, z); | |
} | |
void MoveCamera(float x, float y, float z) { | |
MoveEntity(g_camera, x, y, z); | |
} | |
void MoveCameraX(float x) { | |
MoveEntityX(g_camera, x); | |
} | |
void MoveCameraY(float y) { | |
MoveEntityY(g_camera, y); | |
} | |
void MoveCameraZ(float z) { | |
MoveEntityZ(g_camera, z); | |
} | |
void TurnCamera(float x, float y, float z) { | |
TurnEntity(g_camera, x, y, z); | |
} | |
void TurnCameraX(float x) { | |
TurnEntityX(g_camera, x); | |
} | |
void TurnCameraY(float y) { | |
TurnEntityY(g_camera, y); | |
} | |
void TurnCameraZ(float z) { | |
TurnEntityZ(g_camera, z); | |
} | |
int GetCameraViewX() { | |
return GetViewX(g_camera->view); | |
} | |
int GetCameraViewY() { | |
return GetViewY(g_camera->view); | |
} | |
int GetCameraViewWidth() { | |
return GetViewWidth(g_camera->view); | |
} | |
int GetCameraViewHeight() { | |
return GetViewHeight(g_camera->view); | |
} | |
void SetCameraPerspective(float fov) { | |
SetViewPerspective(g_camera->view, fov); | |
} | |
void SetCameraOrtho(float left, float top, float right, float bottom) { | |
SetViewOrtho(g_camera->view, left, top, right, bottom); | |
} | |
void SetCameraRange(float zn, float zf) { | |
SetViewRange(g_camera->view, zn, zf); | |
} | |
float GetCameraPerspectiveFOV() { | |
return GetViewPerspectiveFOV(g_camera->view); | |
} | |
float GetCameraOrthoLeft() { | |
return GetViewOrthoLeft(g_camera->view); | |
} | |
float GetCameraOrthoTop() { | |
return GetViewOrthoTop(g_camera->view); | |
} | |
float GetCameraOrthoRight() { | |
return GetViewOrthoRight(g_camera->view); | |
} | |
float GetCameraOrthoBottom() { | |
return GetViewOrthoBottom(g_camera->view); | |
} | |
float GetCameraRangeNear() { | |
return GetViewRangeNear(g_camera->view); | |
} | |
float GetCameraRangeFar() { | |
return GetViewRangeFar(g_camera->view); | |
} | |
void EnableCameraClearColor() { | |
EnableViewClearColor(g_camera->view); | |
} | |
void DisableCameraClearColor() { | |
DisableViewClearColor(g_camera->view); | |
} | |
bool_t IsCameraClearColorEnabled() { | |
return IsViewClearColorEnabled(g_camera->view); | |
} | |
void EnableCameraClearDepth() { | |
EnableViewClearDepth(g_camera->view); | |
} | |
void DisableCameraClearDepth() { | |
DisableViewClearDepth(g_camera->view); | |
} | |
bool_t IsCameraClearDepthEnabled() { | |
return IsViewClearDepthEnabled(g_camera->view); | |
} | |
void EnableCameraClearStencil() { | |
EnableViewClearStencil(g_camera->view); | |
} | |
void DisableCameraClearStencil() { | |
DisableViewClearStencil(g_camera->view); | |
} | |
bool_t IsCameraClearStencilEnabled() { | |
return IsViewClearStencilEnabled(g_camera->view); | |
} | |
void SetCameraClearColor(float r, float g, float b, float a) { | |
SetViewClearColor(g_camera->view, r, g, b, a); | |
} | |
float GetCameraClearColorR() { | |
return GetViewClearColorR(g_camera->view); | |
} | |
float GetCameraClearColorG() { | |
return GetViewClearColorG(g_camera->view); | |
} | |
float GetCameraClearColorB() { | |
return GetViewClearColorB(g_camera->view); | |
} | |
float GetCameraClearColorA() { | |
return GetViewClearColorA(g_camera->view); | |
} | |
void SetCameraClearDepth(float z) { | |
SetViewClearDepth(g_camera->view, z); | |
} | |
float GetCameraClearDepth() { | |
return GetViewClearDepth(g_camera->view); | |
} | |
void SetCameraClearStencil(unsigned char mask) { | |
SetViewClearStencil(g_camera->view, mask); | |
} | |
unsigned char GetCameraClearStencil() { | |
return GetViewClearStencil(g_camera->view); | |
} | |
void SetCameraAutoVP(float l, float t, float r, float b) { | |
SetViewAutoVP(g_camera->view, l, t, r, b); | |
} | |
void SetCameraRealVP(int l, int t, int r, int b) { | |
SetViewRealVP(g_camera->view, l, t, r, b); | |
} | |
/* | |
* ========================================================================== | |
* | |
* PRIMITIVES | |
* | |
* ========================================================================== | |
*/ | |
entity_t *NewTriangle(brush_t *brush) { | |
unsigned short *tri; | |
surface_t *surf; | |
entity_t *ent; | |
vertex_t *verts; | |
ent = NewEntity((entity_t *)0); | |
surf = NewSurface(ent); | |
verts = AddSurfaceVertices(surf, 3); | |
tri = AddSurfaceTriangles(surf, 1); | |
SetVertexPosition(&verts[0], -0.5f,-0.5f, 0.0f); | |
SetVertexPosition(&verts[1], 0.0f,+0.5f, 0.0f); | |
SetVertexPosition(&verts[2], +0.5f,-0.5f, 0.0f); | |
SetVertexNormal(&verts[0], 0,0,1); | |
SetVertexNormal(&verts[1], 0,0,1); | |
SetVertexNormal(&verts[2], 0,0,1); | |
tri[0] = 0; | |
tri[1] = 1; | |
tri[2] = 2; | |
AddSurfacePass(surf, brush); | |
return ent; | |
} | |
static uint unorm_color(float r, float g, float b) { | |
union { unsigned char b[4]; unsigned int u; } v; | |
v.b[0] = (unsigned char)(r*255.0f); | |
v.b[1] = (unsigned char)(g*255.0f); | |
v.b[2] = (unsigned char)(b*255.0f); | |
v.b[3] = 0xFF; | |
return v.u; | |
} | |
static uint snorm_color(float rgb[3]) { | |
return unorm_color((rgb[0] + 1)/2, (rgb[1] + 1)/2, (rgb[2] + 1)/2); | |
} | |
static void figureEightTorus_f(float *xyz, float c, float u, float v) { | |
xyz[0] = Cos(u)*(c + Sin(v)*Cos(u) - Sin(2.0f*v)*Sin(u)/2.0f); | |
xyz[1] = Sin(u)*(c + Sin(v)*Cos(u) - Sin(2.0f*v)*Sin(u)/2.0f); | |
xyz[2] = Sin(u)*Sin(v) + Cos(u)*Sin(2.0f*v)/2.0f; | |
} | |
entity_t *NewFigureEightTorus(brush_t *brush, float c, uint segs) { | |
unsigned short *tris, idx; | |
surface_t *surf; | |
entity_t *ent; | |
vertex_t *verts; | |
float vl[3], vh[3]; | |
float u, v, step; | |
int i, j; | |
if(!c) c=1.0f; | |
if(!segs) segs=36; | |
ent = NewEntity((entity_t *)0); | |
surf = NewSurface(ent); | |
step = 360.0f / (float)segs; | |
vl[0] = -1 - c; | |
vl[1] = -1 - c; | |
vl[2] = -1 - c; | |
vh[0] = +1 + c; | |
vh[1] = +1 + c; | |
vh[2] = +1 + c; | |
vl[0] /= 2; | |
vl[1] /= 2; | |
vl[2] /= 2; | |
vh[0] /= 2; | |
vh[1] /= 2; | |
vh[2] /= 2; | |
for(u=0; u<360; u+=step) { | |
for(v=0; v<360; v+=step) { | |
float s0, t0, s1, t1; | |
s0 = u; | |
t0 = v; | |
s1 = u + step; | |
t1 = v + step; | |
idx = GetSurfaceVertexCount(surf); | |
verts = AddSurfaceVertices(surf, 4); | |
tris = AddSurfaceTriangles(surf, 2); | |
figureEightTorus_f(verts[0].xyz, c, s0, t0); | |
figureEightTorus_f(verts[1].xyz, c, s1, t0); | |
figureEightTorus_f(verts[2].xyz, c, s0, t1); | |
figureEightTorus_f(verts[3].xyz, c, s1, t1); | |
for(i=0; i<4; i++) { | |
float rgb[3]; | |
for(j=0; j<3; j++) { | |
verts[i].xyz[j] /= vh[j] - vl[j]; | |
rgb[j] = verts[i].xyz[j]; | |
verts[i].xyz[j] /= 2; | |
} | |
*(uint *)verts[i].color = snorm_color(rgb); | |
} | |
tris[0*3 + 0]=idx + 0; tris[0*3 + 1]=idx + 1; tris[0*3 + 2]=idx + 2; | |
tris[1*3 + 0]=idx + 2; tris[1*3 + 1]=idx + 1; tris[1*3 + 2]=idx + 3; | |
} | |
} | |
AddSurfacePass(surf, brush); | |
return ent; | |
} | |
/* | |
* ========================================================================== | |
* | |
* RENDER QUEUE FUNCTIONS | |
* | |
* ========================================================================== | |
*/ | |
size_t g_numDrawItems = 0; | |
size_t g_maxDrawItems = 0; | |
drawItem_t *g_drawItems = (drawItem_t *)0; | |
void WTF(const char *x) { printf("%s\n", x); fflush(stdout); } | |
drawItem_t *rq_AddDrawItems(size_t numItems) { | |
#define DRAWITEM_GRAN 64 | |
size_t n; | |
if (g_numDrawItems + numItems > g_maxDrawItems) { | |
g_maxDrawItems = g_numDrawItems + numItems; | |
g_maxDrawItems -= g_maxDrawItems%DRAWITEM_GRAN; | |
g_maxDrawItems += DRAWITEM_GRAN; | |
n = g_maxDrawItems*sizeof(drawItem_t); | |
g_drawItems = (drawItem_t *)Memory((void *)g_drawItems, n); | |
} | |
n = g_numDrawItems; | |
g_numDrawItems += numItems; | |
return &g_drawItems[n]; | |
#undef DRAWITEM_GRAN | |
} | |
void rq_AddEntities(entity_t *ent, view_t *v) { | |
const float *M; | |
drawItem_t *di; | |
surface_t *surf; | |
entity_t *chld; | |
brush_t *brush; | |
size_t i, n; | |
float V[16]/*, MV[16]*/; | |
M = GetEntityGlobalMatrix(ent); | |
LoadAffineInverse(V, GetEntityGlobalMatrix(v->ent)); | |
#if 0 | |
AffineMultiply(MV, M, V); | |
Multiply4(ent->MVP, MV, v->M); | |
#else | |
AffineMultiply(ent->MVP, V, M); | |
#endif | |
#if 0 | |
printf("ent->MVP = [ %3.3f, %3.3f, %3.3f, %3.3f,\n", | |
ent->MVP[ 0], ent->MVP[ 4], ent->MVP[ 8], ent->MVP[12]); | |
printf(" %3.3f, %3.3f, %3.3f, %3.3f,\n", | |
ent->MVP[ 1], ent->MVP[ 5], ent->MVP[ 9], ent->MVP[13]); | |
printf(" %3.3f, %3.3f, %3.3f, %3.3f,\n", | |
ent->MVP[ 2], ent->MVP[ 6], ent->MVP[10], ent->MVP[14]); | |
printf(" %3.3f, %3.3f, %3.3f, %3.3f ];\n\n", | |
ent->MVP[ 3], ent->MVP[ 7], ent->MVP[11], ent->MVP[15]); | |
#endif | |
for(surf=ent->s_head; surf; surf=surf->s_next) { | |
n = surf->numPasses; | |
if (!n) | |
continue; | |
#if 0 | |
printf("Adding %i pass%s...\n", (int)n, n!=1 ? "es" : ""); | |
#endif | |
di = rq_AddDrawItems(n); | |
for(i=0; i<n; i++) { | |
brush = surf->passes[i]; | |
di[i].order = i; | |
di[i].M = ent->MVP; | |
di[i].brush = brush; | |
di[i].surf = surf; | |
} | |
} | |
for(chld=ent->head; chld; chld=chld->next) | |
rq_AddEntities(chld, v); | |
} | |
int rq_CmpFunc(const drawItem_t *a, const drawItem_t *b) { | |
if (a->order != b->order) | |
return a->order - b->order; | |
if (a->brush->drawing.zSort|b->brush->drawing.zSort) { | |
if (a->M != b->M) | |
return a->M[14] > b->M[14] ? 1 : -1; | |
} | |
if (a->brush->shader.prog != b->brush->shader.prog) | |
return 1; | |
if (a->brush->drawing.zCmpFunc != b->brush->drawing.zCmpFunc) | |
return 1; | |
if (a->surf != b->surf) | |
return 1; | |
if (a->M != b->M) | |
return a->M[14] < b->M[14] ? 1 : -1; | |
return 0; | |
} | |
void rq_Sort() { | |
qsort((void *)g_drawItems, g_numDrawItems, sizeof(drawItem_t), | |
(int(*)(const void *,const void *))rq_CmpFunc); | |
} | |
size_t rq_Count() { | |
return g_numDrawItems; | |
} | |
size_t rq_Capacity() { | |
return g_maxDrawItems; | |
} | |
void rq_Draw() { | |
const void *inds; | |
drawItem_t *di; | |
vertex_t *verts; | |
size_t i; | |
int numTris; | |
/* | |
* NOTE: This function is purposely NOT optimized | |
*/ | |
gl_CheckError(); | |
glMatrixMode(GL_PROJECTION); | |
gl_CheckError(); | |
glLoadMatrixf(GetViewMatrix(GetCameraEntity()->view)); | |
gl_CheckError(); | |
glMatrixMode(GL_MODELVIEW); | |
gl_CheckError(); | |
glEnable(GL_DEPTH_TEST); | |
gl_CheckError(); | |
for(i=0; i<g_numDrawItems; i++) { | |
di = &g_drawItems[i]; | |
if (!di->brush->drawing.isVisible) | |
continue; | |
verts = di->surf->verts; | |
inds = (const void *)di->surf->inds; | |
if (!verts || !inds) | |
continue; | |
if (di->brush->lighting.isLit) | |
glEnable(GL_LIGHTING); | |
else | |
glDisable(GL_LIGHTING); | |
gl_CheckError(); | |
switch(di->brush->drawing.cullMode) { | |
case kCM_None: | |
glDisable(GL_CULL_FACE); | |
break; | |
case kCM_Front: | |
glEnable(GL_CULL_FACE); | |
glCullFace(GL_FRONT); | |
break; | |
case kCM_Back: | |
glEnable(GL_CULL_FACE); | |
glCullFace(GL_BACK); | |
break; | |
case kCM_Both: | |
glEnable(GL_CULL_FACE); | |
glCullFace(GL_FRONT_AND_BACK); | |
break; | |
default: | |
break; | |
} | |
gl_CheckError(); | |
switch(di->brush->drawing.zCmpFunc) { | |
case kCF_Never: glDepthFunc(GL_NEVER); break; | |
case kCF_Less: glDepthFunc(GL_LESS); break; | |
case kCF_LessEqual: glDepthFunc(GL_LEQUAL); break; | |
case kCF_Equal: glDepthFunc(GL_EQUAL); break; | |
case kCF_NotEqual: glDepthFunc(GL_NOTEQUAL); break; | |
case kCF_GreaterEqual: glDepthFunc(GL_GEQUAL); break; | |
case kCF_Greater: glDepthFunc(GL_GREATER); break; | |
case kCF_Always: glDepthFunc(GL_ALWAYS); break; | |
default: | |
break; | |
} | |
gl_CheckError(); | |
/*di->brush->drawing.zTest = TRUE;*/ /*HACK*/ | |
if (di->brush->drawing.zTest) | |
glEnable(GL_DEPTH_TEST); | |
else | |
glDisable(GL_DEPTH_TEST); | |
gl_CheckError(); | |
glDepthMask(di->brush->drawing.zWrite); | |
gl_CheckError(); | |
numTris = di->surf->numInds/3; | |
R->UseProgram(di->brush->shader.prog); | |
gl_CheckError(); | |
glLoadMatrixf(di->M); | |
gl_CheckError(); | |
glEnableClientState(GL_VERTEX_ARRAY); | |
gl_CheckError(); | |
glEnableClientState(GL_COLOR_ARRAY); | |
gl_CheckError(); | |
glVertexPointer(3, GL_FLOAT, sizeof(vertex_t), &verts->xyz); | |
gl_CheckError(); | |
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex_t), &verts->color); | |
gl_CheckError(); | |
glNormalPointer(GL_FLOAT, sizeof(vertex_t), &verts->norm); | |
gl_CheckError(); | |
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex_t), &verts->st); | |
gl_CheckError(); | |
//printf("DRAW: verts=0x%p; tris=0x%p; numTris=%u\n", &verts->xyz, (void *)inds, numTris); | |
glDrawElements(GL_TRIANGLES, numTris*3, GL_UNSIGNED_SHORT, inds); | |
gl_CheckError(); | |
} | |
g_numDrawItems = 0; | |
} | |
/* | |
* ========================================================================== | |
* | |
* OPENGL FUNCTIONS | |
* | |
* ========================================================================== | |
*/ | |
bool_t gl_IsExtensionSupported(const char *extension) { | |
return glfwExtensionSupported(extension) ? TRUE : FALSE; | |
} | |
void gl_RequireExtension(const char *extension) { | |
if (!gl_IsExtensionSupported(extension)) | |
ErrorExit("Need GL extension \'%s\'", extension); | |
} | |
fn_t gl_Proc(const char *proc) { | |
fnptr_t x; | |
x.p = glfwGetProcAddress(proc); | |
if (!x.p) | |
ErrorExit("GL function not found \'%s\'", proc); | |
return x.fn; | |
} | |
void gl_CheckError_(const char *file, int line) { | |
const char *err; | |
switch(glGetError()) { | |
case GL_NO_ERROR: return; | |
case GL_INVALID_ENUM: err="GL_INVALID_ENUM"; break; | |
case GL_INVALID_VALUE: err="GL_INVALID_VALUE"; break; | |
case GL_INVALID_OPERATION: err="GL_INVALID_OPERATION"; break; | |
case GL_STACK_OVERFLOW: err="GL_STACK_OVERFLOW"; break; | |
case GL_STACK_UNDERFLOW: err="GL_STACK_UNDERFLOW"; break; | |
case GL_OUT_OF_MEMORY: err="GL_OUT_OF_MEMORY"; break; | |
default: err="(unknown)"; break; | |
} | |
ErrorFileExit(file, line, "glGetError() = %s\n", err); | |
} | |
/* | |
* ========================================================================== | |
* | |
* SCREEN | |
* | |
* ========================================================================== | |
*/ | |
void GLFWAPI ReshapeWindow(int w, int h) { | |
RecalcAllViewports(w, h); | |
} | |
void scr_Init(glScreen_t *desc) { | |
#define APPLYDEFAULT(x,y) if(!(x))x=y | |
#define ASPECT(x,y) ((int)(((double)(x))/((double)(y)))) | |
glScreen_t internalScreenDesc; | |
glfwInit(); | |
atexit(glfwTerminate); | |
if (!desc) { | |
memset(&internalScreenDesc, 0, sizeof(internalScreenDesc)); | |
desc = &internalScreenDesc; | |
} | |
APPLYDEFAULT(desc->width , 640); | |
APPLYDEFAULT(desc->height , ASPECT(desc->width, 4.0/3.0)); | |
APPLYDEFAULT(desc->r , 8); | |
APPLYDEFAULT(desc->g , 8); | |
APPLYDEFAULT(desc->b , 8); | |
APPLYDEFAULT(desc->a , 8); | |
APPLYDEFAULT(desc->depth , 24); | |
APPLYDEFAULT(desc->stencil, 8); | |
if (!glfwOpenWindow(desc->width, desc->height, desc->r, desc->g, desc->b, | |
desc->a, desc->depth, desc->stencil, GLFW_WINDOW)) | |
exit(EXIT_FAILURE); | |
glfwSetWindowSizeCallback(ReshapeWindow); | |
printf("GLFW_ACCELERATED=%i\n", glfwGetWindowParam(GLFW_ACCELERATED)); | |
printf("GLFW_RED_BITS=%i\n", glfwGetWindowParam(GLFW_RED_BITS)); | |
printf("GLFW_GREEN_BITS=%i\n", glfwGetWindowParam(GLFW_GREEN_BITS)); | |
printf("GLFW_BLUE_BITS=%i\n", glfwGetWindowParam(GLFW_BLUE_BITS)); | |
printf("GLFW_ALPHA_BITS=%i\n", glfwGetWindowParam(GLFW_ALPHA_BITS)); | |
printf("GLFW_DEPTH_BITS=%i\n", glfwGetWindowParam(GLFW_DEPTH_BITS)); | |
printf("GLFW_STENCIL_BITS=%i\n", glfwGetWindowParam(GLFW_STENCIL_BITS)); | |
printf("\n"); | |
printf("GL Version: %s\n", (const char *)glGetString(GL_VERSION)); | |
printf("GL Renderer: %s\n", (const char *)glGetString(GL_RENDERER)); | |
printf("GL Vendor: %s\n", (const char *)glGetString(GL_VENDOR)); | |
printf("GL Extensions: %s\n", (const char *)glGetString(GL_EXTENSIONS)); | |
printf("\n"); | |
atexit(&scr_Fini); | |
gl_RequireExtension("GL_ARB_shader_objects"); | |
gl_RequireExtension("GL_ARB_shading_language_100"); | |
#undef ASPECT | |
#undef APPLYDEFAULT | |
} | |
void scr_Fini() { | |
glfwCloseWindow(); | |
} | |
bool_t scr_IsOpen() { | |
return glfwGetWindowParam(GLFW_OPENED) ? TRUE : FALSE; | |
} | |
/* | |
* ========================================================================== | |
* | |
* RENDERER | |
* | |
* ========================================================================== | |
*/ | |
renderer_t *R = (renderer_t *)0; | |
#if 0 | |
static const char *g_tileMap_fragSrc = | |
"#version 110\n" | |
"\n" | |
"void main() {\n" | |
" gl_FragColor = vec4(0.8f,0.8f,0.0f, 1.0f);\n" | |
"}\n" | |
"\n"; | |
#endif | |
entity_t *g_triangle = (entity_t *)0; | |
brush_t *g_defaultBrush = (brush_t *)0; | |
void r_Init() { | |
int w, h; | |
if (R) | |
return; | |
R = AllocStruct(renderer_t); | |
atexit(&r_Fini); | |
#if 0 | |
*(fn_t *)&R->ClearColor = (fn_t)glClearColor; | |
*(fn_t *)&R->ClearDepth = (fn_t)glClearDepth; | |
*(fn_t *)&R->ClearStencil = (fn_t)glClearStencil; | |
*(fn_t *)&R->Clear = (fn_t)glClear; | |
#endif | |
*(fn_t *)&R->CreateShader = gl_Proc("glCreateShaderObjectARB"); | |
*(fn_t *)&R->ShaderSource = gl_Proc("glShaderSourceARB"); | |
*(fn_t *)&R->CompileShader = gl_Proc("glCompileShaderARB"); | |
*(fn_t *)&R->CreateProgram = gl_Proc("glCreateProgramObjectARB"); | |
*(fn_t *)&R->AttachObject = gl_Proc("glAttachObjectARB"); | |
*(fn_t *)&R->LinkProgram = gl_Proc("glLinkProgramARB"); | |
*(fn_t *)&R->UseProgram = gl_Proc("glUseProgramObjectARB"); | |
*(fn_t *)&R->GetShaderInfoLog = gl_Proc("glGetInfoLogARB"); | |
*(fn_t *)&R->GetProgramInfoLog = gl_Proc("glGetInfoLogARB"); | |
*(fn_t *)&R->DeleteShader = gl_Proc("glDeleteObjectARB"); | |
*(fn_t *)&R->DeleteProgram = gl_Proc("glDeleteObjectARB"); | |
g_defaultBrush = NewBrush(); | |
#if 0 | |
SetBrushShader(g_defaultBrush, (const char *)0, g_tileMap_fragSrc); | |
#endif | |
SetBrushCullMode(g_defaultBrush, kCM_None); | |
/*DisableBrushZTest(g_defaultBrush);*/ | |
EnableBrushRendering(g_defaultBrush); | |
DisableBrushLighting(g_defaultBrush); | |
NewCamera(); | |
glfwGetWindowSize(&w, &h); | |
RecalcAllViewports(w, h); | |
#if 1 | |
SetCameraEntity(NewCamera()); | |
SetCameraAutoVP(0.6f,0.6f, 0.9f,0.9f); | |
SetCameraClearColor(0.7f,0.7f,0.7f, 1.0f); | |
//DisableCameraClearColor(); | |
#endif | |
#if 0 | |
g_triangle = NewTriangle(g_defaultBrush); | |
#else | |
g_triangle = NewFigureEightTorus(g_defaultBrush, 1.0f, 36); | |
#endif | |
} | |
void r_Fini() { | |
DeleteAllEntities(); | |
R = (renderer_t *)Memory((void *)R, 0); | |
} | |
/* | |
* ------------------------------- | |
* TODO: Frustum-culling of sorts. | |
* ------------------------------- | |
*/ | |
void r_DrawView(view_t *view) { | |
GLbitfield clearBits; | |
int w, h; | |
int vp[4]; | |
g_camera = view->ent; | |
/* specify the viewport and the scissor rectangle */ | |
glfwGetWindowSize(&w, &h); | |
RecalcViewport(view, w, h); | |
vp[0] = view->vpReal[0]; | |
vp[1] = view->vpReal[1]; | |
vp[2] = view->vpReal[2] - view->vpReal[0]; | |
vp[3] = view->vpReal[3] - view->vpReal[1]; | |
glViewport(vp[0], vp[1], vp[2], vp[3]); | |
gl_CheckError(); | |
glDepthRange(0, 1); | |
gl_CheckError(); | |
glEnable(GL_SCISSOR_TEST); | |
gl_CheckError(); | |
glScissor(vp[0], vp[1], vp[2], vp[3]); | |
gl_CheckError(); | |
/* perform the clear operation */ | |
clearBits = 0; | |
clearBits |= view->clear.clearColor ? GL_COLOR_BUFFER_BIT : 0; | |
clearBits |= view->clear.clearDepth ? GL_DEPTH_BUFFER_BIT : 0; | |
clearBits |= view->clear.clearStencil ? GL_STENCIL_BUFFER_BIT : 0; | |
if (clearBits) { | |
/*R->ClearColor(view->clear.color[0], view->clear.color[1], | |
view->clear.color[2], view->clear.color[3]);*/ | |
glClearColor(view->clear.color[0], view->clear.color[1], | |
view->clear.color[2], view->clear.color[3]); | |
gl_CheckError(); | |
/*R->ClearDepth(view->clear.depth);*/ | |
glClearDepth(view->clear.depth); | |
gl_CheckError(); | |
/*R->ClearStencil(view->clear.stencil);*/ | |
glClearStencil(view->clear.stencil); | |
gl_CheckError(); | |
/*R->Clear(clearBits);*/ | |
glClear(clearBits); | |
gl_CheckError(); | |
} | |
/* add the entities specified to the render queue */ | |
#if 1 | |
rq_AddEntities(g_triangle, view); | |
#else | |
{ | |
entity_t *ent; | |
for(ent=g_ent_head; ent; ent=ent->next) | |
rq_AddEntities(ent, view); | |
} | |
#endif | |
/* sort then draw the entities within the queue */ | |
/*WTF("Sorting queue...");*/ | |
rq_Sort(); | |
/*WTF("Drawing (sorted) queue...");*/ | |
rq_Draw(); | |
/*WTF("Done drawing queue");*/ | |
} | |
void r_Frame(double deltaTime) { | |
entity_t *cam; | |
view_t *view; | |
/*deltaTime will later be used for animations*/ | |
if(deltaTime){/*unused*/} | |
cam = g_camera; | |
for(view=g_view_head; view; view=view->next) { | |
/*WTF("Drawing view...");*/ | |
r_DrawView(view); | |
/*WTF("Done drawing view");*/ | |
} | |
g_camera = cam; | |
/* sync */ | |
glfwSwapBuffers(); | |
} | |
/* | |
* ========================================================================== | |
* | |
* MAIN PROGRAM | |
* | |
* ========================================================================== | |
*/ | |
void update(float time, float deltaTime) { | |
/* hacked in processing for frame animation */ | |
#if 1 | |
TurnEntityX(g_triangle, 45.0f*deltaTime); | |
TurnEntityY(g_triangle, -45.0f*deltaTime); | |
/*TurnEntityZ(g_triangle, 45.0f*time);*/ | |
#endif | |
#if 1 | |
SetEntityPosition(g_triangle, 0,0, 1 + (1 + Sin(90.0f*time))/2*4); | |
#else | |
SetEntityPosition(g_triangle, 0, 0, 1); | |
#endif | |
} | |
int main() { | |
double newTime, oldTime, deltaTime; | |
/* initialization */ | |
scr_Init((glScreen_t *)0); | |
r_Init(); | |
/* main loop */ | |
newTime = glfwGetTime(); | |
while(scr_IsOpen()) { | |
/* timing */ | |
oldTime = newTime; | |
newTime = glfwGetTime(); | |
deltaTime = newTime - oldTime; | |
/* render a frame */ | |
update((float)newTime, (float)deltaTime); | |
r_Frame(deltaTime); | |
} | |
/* done */ | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment