Skip to content

Instantly share code, notes, and snippets.

@NotKyon
Last active December 12, 2017 08:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NotKyon/a4b9554fec955538bcde383d8e682409 to your computer and use it in GitHub Desktop.
Save NotKyon/a4b9554fec955538bcde383d8e682409 to your computer and use it in GitHub Desktop.
/*
*/
/*
*/ //========================================//
/* // 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