begin splitting up the example into a single example 200 LOC target

This commit is contained in:
iann 2025-11-08 12:20:35 +09:00
parent 3617ebd970
commit 8bc6606ebe
7 changed files with 999 additions and 63 deletions

View File

@ -522,6 +522,8 @@ CORE = \
core/core_3d_camera_split_screen \ core/core_3d_camera_split_screen \
core/core_3d_picking \ core/core_3d_picking \
core/core_3d_fixed_function_didactic \ core/core_3d_fixed_function_didactic \
core/core_3d_camera_view_opengl11 \
core/core_3d_camera_view_opengl33 \
core/core_automation_events \ core/core_automation_events \
core/core_basic_screen_manager \ core/core_basic_screen_manager \
core/core_basic_window \ core/core_basic_window \

View File

@ -0,0 +1,382 @@
/*******************************************************************************************
*
* raylib [core] example - Camera View
*
* Example complexity rating: [] 4/4
*
* Example originally created with raylib 6.0? (target)
*
* Example contributed by IANN (@meisei4) and reviewed by Ramon Santamaria (@raysan5) and community
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025-2025 @meisei4
*
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
#include "rlgl.h"
#include <stdlib.h>
#include <string.h>
#define BAHAMA_BLUE CLITERAL(Color){ 0, 102, 153, 255 }
#define SUNFLOWER CLITERAL(Color){ 255, 204, 153, 255 }
#define ANAKIWA CLITERAL(Color){ 153, 204, 255, 255 }
#define MARINER CLITERAL(Color){ 51, 102, 204, 255 }
#define NEON_CARROT CLITERAL(Color){ 255, 153, 51, 255 }
#define EGGPLANT CLITERAL(Color){ 102, 68, 102, 255 }
#define HOPBUSH CLITERAL(Color){ 204, 102, 153, 255 }
#define LILAC CLITERAL(Color){ 204, 153, 204, 255 }
#define RED_DAMASK CLITERAL(Color){ 221, 102, 68, 255 }
#define CHESTNUT_ROSE CLITERAL(Color){ 204, 102, 102, 255 }
typedef unsigned short Triangle[3];
enum Flags
{
FLAG_ASPECT = 1u<<0,
FLAG_PAUSE = 1u<<1,
FLAG_JUGEMU = 1u<<2,
FLAG_ORTHO = 1u<<3,
GEN_CUBE = 1u<<4,
GEN_SPHERE = 1u<<5,
GEN_KNOT = 1u<<6
};
static unsigned int gflags = FLAG_ASPECT | FLAG_JUGEMU | GEN_CUBE;
#define ASPECT_CORRECT() ((gflags & FLAG_ASPECT) != 0)
#define PAUSED() ((gflags & FLAG_PAUSE) != 0)
#define JUGEMU_MODE() ((gflags & FLAG_JUGEMU) != 0)
#define ORTHO_MODE() ((gflags & FLAG_ORTHO) != 0)
#define TOGGLE(K, F) do { if (IsKeyPressed(K)) { gflags ^= (F); } } while (0)
static unsigned int targetMesh = 0;
#define NUM_MODELS 3
#define CYCLE_MESH(K, I, F) do { if (IsKeyPressed(K)) { targetMesh = (I); gflags = (gflags & ~(GEN_CUBE|GEN_SPHERE|GEN_KNOT)) | (F); } } while (0)
static int fontSize = 20;
static float angularVelocity = 1.25f;
static float fovyPerspective = 60.0f;
static float nearPlaneHeightOrthographic = 1.0f;
static float blendScalar = 5.0f;
static Vector3 modelScale = { 1.0f, 1.0f, 1.0f };
static Vector3 modelPos = { 0.0f, 0.0f, 0.0f };
static void UpdateSpatialFrame(Camera3D *main, float aspect, float near, float far, Mesh *spatialFrame);
static void DrawSpatialFrame(Mesh *spatialFrame);
static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D *perspectiveCorrectTexture, float rotation);
static void AlphaMaskPunchOut(Image *rgba, Image *mask, unsigned char threshold);
static void FillVertexColors(Mesh *mesh);
static void OrbitSpace(Camera3D *jugemu, float dt);
static Vector3 TranslateRotateScale(Vector3 coordinate, Vector3 pos, Vector3 scale, float rotation);
static Vector3 Intersect(Camera3D *main, float near, Vector3 worldCoord);
static float OrthoBlendFactor(float dt);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - fixed function didactic");
Texture2D perspectiveCorrectTexture = (Texture2D){ 0 };
float near = 1.0f;
float far = 3.0f;
float aspect = (float)GetScreenWidth()/(float)GetScreenHeight();
nearPlaneHeightOrthographic = 2.0f*near*tanf(DEG2RAD*fovyPerspective*0.5f);
float meshRotation = 0.0f;
Camera3D main = { 0 };
main.position = (Vector3){ 0.0f, 0.0f, 2.0f };
main.target = modelPos;
main.up = (Vector3){ 0.0f, 1.0f, 0.0f };
main.projection = (ORTHO_MODE())? CAMERA_ORTHOGRAPHIC : CAMERA_PERSPECTIVE;
main.fovy = (ORTHO_MODE())? nearPlaneHeightOrthographic: fovyPerspective;
Camera3D jugemu = (Camera3D){ 0 };
jugemu.position = (Vector3){ 3.0f, 1.0f, 3.0f };
jugemu.target = modelPos;
jugemu.up = (Vector3){ 0.0f, 1.0f, 0.0f };
jugemu.fovy = fovyPerspective;
jugemu.projection = CAMERA_PERSPECTIVE;
Model models[NUM_MODELS] = { 0 };
models[0] = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
models[1] = LoadModelFromMesh(GenMeshSphere(0.5f, 8, 8));
models[2] = LoadModelFromMesh(GenMeshKnot(1.0f, 1.0f, 16, 128));
for (int i = 0; i < NUM_MODELS; i++)
{
Mesh *mesh = &models[i].meshes[0];
if (!mesh->indices)
{
mesh->indices = RL_CALLOC(mesh->vertexCount, sizeof(unsigned short));
for (int j = 0; j < mesh->vertexCount; j++) mesh->indices[j] = (unsigned short)j;
mesh->triangleCount = mesh->vertexCount/3;
}
FillVertexColors(mesh);
}
Mesh spatialFrame = GenMeshCube(1.0f, 1.0f, 1.0f);
spatialFrame.colors = RL_CALLOC(spatialFrame.vertexCount, sizeof(Color));
for (int i = 0; i < spatialFrame.vertexCount; i++) ((Color *)spatialFrame.colors)[i] = (Color){ 255, 255, 255, 0 };
for (int i = 0; i < 4; i++) ((Color *)spatialFrame.colors)[i].a = 255;
Model spatialFrameModel = LoadModelFromMesh(spatialFrame);
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
while (!WindowShouldClose())
{
// Update
//----------------------------------------------------------------------------------
aspect = (float)GetScreenWidth()/(float)GetScreenHeight();
TOGGLE(KEY_Q, FLAG_ASPECT);
TOGGLE(KEY_SPACE, FLAG_PAUSE);
TOGGLE(KEY_J, FLAG_JUGEMU);
TOGGLE(KEY_O, FLAG_ORTHO);
CYCLE_MESH(KEY_ONE, 0, GEN_CUBE);
CYCLE_MESH(KEY_TWO, 1, GEN_SPHERE);
CYCLE_MESH(KEY_THREE, 2, GEN_KNOT);
OrthoBlendFactor(GetFrameTime());
if (!PAUSED()) meshRotation -= angularVelocity*GetFrameTime();
OrbitSpace(&jugemu, GetFrameTime());
main.projection = (ORTHO_MODE())? CAMERA_ORTHOGRAPHIC : CAMERA_PERSPECTIVE;
main.fovy = (ORTHO_MODE())? nearPlaneHeightOrthographic : fovyPerspective;
Model *displayModel = &models[targetMesh];
PerspectiveCorrectCapture(&main, displayModel, &perspectiveCorrectTexture, meshRotation);
UpdateSpatialFrame(&main, aspect, near, far, &spatialFrame);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(BLACK);
if (JUGEMU_MODE()) BeginMode3D(jugemu); else BeginMode3D(main);
Vector3 depth = Vector3Normalize(Vector3Subtract(main.target, main.position));
Vector3 right = Vector3Normalize(Vector3CrossProduct(depth, main.up));
Vector3 up = Vector3Normalize(Vector3CrossProduct(right, depth));
DrawLine3D(main.position, Vector3Add(main.position, right), NEON_CARROT);
DrawLine3D(main.position, Vector3Add(main.position, up), LILAC);
DrawLine3D(main.position, Vector3Add(main.position, depth), MARINER);
if (JUGEMU_MODE()) DrawSpatialFrame(&spatialFrame);
DrawModelEx(*displayModel, modelPos, (Vector3){ 0.0f, 1.0f, 0.0f }, RAD2DEG*meshRotation, modelScale, WHITE);
Color *cacheColors = (Color *)displayModel->meshes[0].colors;
displayModel->meshes[0].colors = NULL;
unsigned int cacheID = displayModel->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id;
displayModel->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = rlGetTextureIdDefault();
DrawModelWiresEx(*displayModel, modelPos, (Vector3){ 0.0f, 1.0f, 0.0f }, RAD2DEG*meshRotation, modelScale, MARINER);
rlSetPointSize(4.0f);
DrawModelPointsEx(*displayModel, modelPos, (Vector3){ 0.0f, 1.0f, 0.0f }, RAD2DEG*meshRotation, modelScale, LILAC);
displayModel->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = cacheID;
displayModel->meshes[0].colors = (unsigned char *)cacheColors;
if (JUGEMU_MODE())
{
Vector3 *vertices = (Vector3 *)displayModel->meshes[0].vertices;
Triangle *triangles = (Triangle *)displayModel->meshes[0].indices;
for (int i = 0; i < displayModel->meshes[0].triangleCount; i++)
{
Vector3 a = TranslateRotateScale(vertices[triangles[i][0]], modelPos, modelScale, meshRotation);
Vector3 b = TranslateRotateScale(vertices[triangles[i][1]], modelPos, modelScale, meshRotation);
Vector3 c = TranslateRotateScale(vertices[triangles[i][2]], modelPos, modelScale, meshRotation);
if (Vector3DotProduct(Vector3Normalize(Vector3CrossProduct(Vector3Subtract(b, a), Vector3Subtract(c, a))), depth) > 0.0f) continue;
DrawLine3D(a, Intersect(&main, near, a), (Color){ RED_DAMASK.r, RED_DAMASK.g, RED_DAMASK.b, 20 });
DrawLine3D(b, Intersect(&main, near, b), (Color){ RED_DAMASK.r, RED_DAMASK.g, RED_DAMASK.b, 20 });
DrawLine3D(c, Intersect(&main, near, c), (Color){ RED_DAMASK.r, RED_DAMASK.g, RED_DAMASK.b, 20 });
}
}
spatialFrameModel.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = perspectiveCorrectTexture;
if (JUGEMU_MODE()) DrawModel(spatialFrameModel, modelPos, 1.0f, WHITE);
EndMode3D();
DrawText("[1]: CUBE [2]: SPHERE [3]: KNOT", 12, 12, fontSize, NEON_CARROT);
DrawText("ARROWS: MOVE | SPACEBAR: PAUSE", 12, 38, fontSize, NEON_CARROT);
DrawText("W S : ZOOM ", 12, 64, fontSize, NEON_CARROT);
DrawText((targetMesh == 0)? "GEN_CUBE" : (targetMesh == 1)? "GEN_SPHERE" : "GEN_KNOT", 12, 205, fontSize, NEON_CARROT);
DrawText("ASPECT [ Q ]:", 12, 392, fontSize, SUNFLOWER);
DrawText((ASPECT_CORRECT())? "CORRECT" : "INCORRECT", 230, 392, fontSize, (ASPECT_CORRECT())? ANAKIWA : CHESTNUT_ROSE);
DrawText("LENS [ O ]:", 510, 366, fontSize, SUNFLOWER);
DrawText((ORTHO_MODE())? "ORTHOGRAPHIC" : "PERSPECTIVE", 630, 366, fontSize, (ORTHO_MODE())? BAHAMA_BLUE : ANAKIWA);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadModel(models[0]);
UnloadModel(models[1]);
UnloadModel(models[2]);
UnloadModel(spatialFrameModel);
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}
static void UpdateSpatialFrame(Camera3D *main, float aspect, float near, float far, Mesh *spatialFrame)
{
Vector3 depth = Vector3Normalize(Vector3Subtract(main->target, main->position));
Vector3 right = Vector3Normalize(Vector3CrossProduct(depth, main->up));
Vector3 up = Vector3Normalize(Vector3CrossProduct(right, depth));
float halfHNear = Lerp(near*tanf(DEG2RAD*fovyPerspective*0.5f), 0.5f*nearPlaneHeightOrthographic, OrthoBlendFactor(0.0f));
float halfWNear = halfHNear*aspect;
float halfHFar = Lerp(far*tanf(DEG2RAD*fovyPerspective*0.5f), 0.5f*nearPlaneHeightOrthographic, OrthoBlendFactor(0.0f));
float halfWFar = halfHFar*aspect;
float halfDepth = 0.5f*(far - near);
Vector3 centerNear = Vector3Add(main->position, Vector3Scale(depth, near));
for (int i = 0; i < spatialFrame->vertexCount; ++i)
{
Vector3 offset = Vector3Subtract(((Vector3 *)spatialFrame->vertices)[i], centerNear);
float xSign = (Vector3DotProduct(offset, right) >= 0.0f)? 1.0f : -1.0f;
float ySign = (Vector3DotProduct(offset, up) >= 0.0f)? 1.0f : -1.0f;
float farMask = (Vector3DotProduct(offset, depth) > halfDepth)? 1.0f : 0.0f;
float finalHalfW = halfWNear + farMask*(halfWFar - halfWNear);
float finalHalfH = halfHNear + farMask*(halfHFar - halfHNear);
Vector3 center = Vector3Add(centerNear, Vector3Scale(depth, farMask*2.0f*halfDepth));
((Vector3 *)spatialFrame->vertices)[i] = Vector3Add(center, Vector3Add(Vector3Scale(right, xSign*finalHalfW), Vector3Scale(up, ySign*finalHalfH)));
}
}
static void DrawSpatialFrame(Mesh *spatialFrame)
{
static int frontFaces[4][2] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 } };
static int backFaces[4][2] = { { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 } };
static int ribFaces[4][2] = { { 0, 4 }, { 1, 7 }, { 2, 6 }, { 3, 5 } };
static int (*faces[3])[2] = { frontFaces, backFaces, ribFaces };
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; j++)
{
Vector3 startPosition = ((Vector3 *)spatialFrame->vertices)[faces[i][j][0]];
Vector3 endPosition = ((Vector3 *)spatialFrame->vertices)[faces[i][j][1]];
DrawLine3D(startPosition, endPosition, (i == 0)? NEON_CARROT : (i == 1)? EGGPLANT : HOPBUSH);
}
}
static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D *perspectiveCorrectTexture, float rotation)
{
ClearBackground(BLACK);
BeginMode3D(*main);
DrawModelEx(*model, modelPos, (Vector3){ 0.0f, 1.0f, 0.0f }, RAD2DEG*rotation, modelScale, WHITE);
Color *cacheColors = (Color *)model->meshes[0].colors;
model->meshes[0].colors = NULL;
DrawModelWiresEx(*model, modelPos, (Vector3){ 0.0f, 1.0f, 0.0f }, RAD2DEG*rotation, modelScale, MARINER);
model->meshes[0].colors = (unsigned char *)cacheColors;
EndMode3D();
Image rgba = LoadImageFromScreen();
ImageFormat(&rgba, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
ClearBackground(BLACK);
BeginMode3D(*main);
Texture2D cacheTexture = model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture;
Color cacheMaterialColor = model->materials[0].maps[MATERIAL_MAP_ALBEDO].color;
model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture = (Texture2D){ 0 };
model->materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
DrawModelEx(*model, modelPos, (Vector3){ 0.0f, 1.0f, 0.0f }, RAD2DEG*rotation, modelScale, WHITE);
model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture = cacheTexture;
model->materials[0].maps[MATERIAL_MAP_ALBEDO].color = cacheMaterialColor;
EndMode3D();
Image mask = LoadImageFromScreen();
AlphaMaskPunchOut(&rgba, &mask, 1);
ImageFlipVertical(&rgba);
if ((perspectiveCorrectTexture->id != 0))
UpdateTexture(*perspectiveCorrectTexture, rgba.data);
else
*perspectiveCorrectTexture = LoadTextureFromImage(rgba);
UnloadImage(mask);
UnloadImage(rgba);
}
static void OrbitSpace(Camera3D *jugemu, float dt)
{
float radius = Vector3Length(jugemu->position);
float azimuth = atan2f(jugemu->position.z, jugemu->position.x);
float horizontalRadius = sqrtf(jugemu->position.x*jugemu->position.x + jugemu->position.z*jugemu->position.z);
float elevation = atan2f(jugemu->position.y, horizontalRadius);
if (IsKeyDown(KEY_LEFT)) azimuth += 1.0f*dt;
if (IsKeyDown(KEY_RIGHT)) azimuth -= 1.0f*dt;
if (IsKeyDown(KEY_UP)) elevation += 1.0f*dt;
if (IsKeyDown(KEY_DOWN)) elevation -= 1.0f*dt;
if (IsKeyDown(KEY_W)) radius -= 1.0f*dt;
if (IsKeyDown(KEY_S)) radius += 1.0f*dt;
elevation = Clamp(elevation, -PI/2 + 0.1f, PI/2 - 0.1f);
jugemu->position.x = Clamp(radius, 0.25f, 10.0f)*cosf(elevation)*cosf(azimuth);
jugemu->position.y = Clamp(radius, 0.25f, 10.0f)*sinf(elevation);
jugemu->position.z = Clamp(radius, 0.25f, 10.0f)*cosf(elevation)*sinf(azimuth);
}
static void AlphaMaskPunchOut(Image *rgba, Image *mask, unsigned char threshold)
{
Image maskCopy = ImageCopy(*mask);
ImageFormat(&maskCopy, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
ImageFormat(rgba, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
unsigned char *maskGrayScale = maskCopy.data;
Color *colors = rgba->data;
int pixelCount = rgba->width*rgba->height;
for (size_t i = 0; i < pixelCount; ++i) colors[i].a = (maskGrayScale[i] > threshold)? 255 : 0;
UnloadImage(maskCopy);
}
static void FillVertexColors(Mesh *mesh)
{
if (!mesh->colors) mesh->colors = RL_CALLOC(mesh->vertexCount, sizeof(Color));
Color *colors = (Color *)mesh->colors;
Vector3 *vertices = (Vector3 *)mesh->vertices;
BoundingBox bounds = GetMeshBoundingBox(*mesh);
for (int i = 0; i < mesh->vertexCount; ++i)
{
Vector3 vertex = vertices[i];
float nx = (vertex.x - 0.5f*(bounds.min.x + bounds.max.x))/(0.5f*(bounds.max.x - bounds.min.x));
float ny = (vertex.y - 0.5f*(bounds.min.y + bounds.max.y))/(0.5f*(bounds.max.y - bounds.min.y));
float nz = (vertex.z - 0.5f*(bounds.min.z + bounds.max.z))/(0.5f*(bounds.max.z - bounds.min.z));
float len = sqrtf(nx*nx + ny*ny + nz*nz);
colors[i] = (Color){ lrintf(127.5f*(nx/len + 1.0f)), lrintf(127.5f*(ny/len + 1.0f)), lrintf(127.5f*(nz/len + 1.0f)), 255 };
}
}
static Vector3 TranslateRotateScale(Vector3 coordinate, Vector3 pos, Vector3 scale, float rotation)
{
return Vector3Transform(coordinate, MatrixMultiply(MatrixMultiply(MatrixScale(scale.x, scale.y, scale.z), MatrixRotateY(rotation)), MatrixTranslate(pos.x, pos.y, pos.z)));
}
static Vector3 Intersect(Camera3D *main, float near, Vector3 worldCoord)
{
Vector3 viewDir = Vector3Normalize(Vector3Subtract(main->target, main->position));
Vector3 mainCameraToPoint = Vector3Subtract(worldCoord, main->position);
float depthAlongView = Vector3DotProduct(mainCameraToPoint, viewDir);
Vector3 centerNearPlane = Vector3Add(main->position, Vector3Scale(viewDir, near));
if (depthAlongView <= 0.0f) return centerNearPlane;
float scaleToNear = near/depthAlongView;
Vector3 resultPerspective = Vector3Add(main->position, Vector3Scale(mainCameraToPoint, scaleToNear));
Vector3 resultOrtho = Vector3Add(worldCoord, Vector3Scale(viewDir, Vector3DotProduct(Vector3Subtract(centerNearPlane, worldCoord), viewDir)));
return Vector3Lerp(resultPerspective, resultOrtho, OrthoBlendFactor(0.0f));
}
static float OrthoBlendFactor(float dt)
{
static float blend = 0.0f;
if (dt > 0.0f) blend = Clamp(blend + ((ORTHO_MODE())? 1.0f : -1.0f)*blendScalar*dt, 0.0f, 1.0f);
return blend;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -0,0 +1,407 @@
/*******************************************************************************************
*
* raylib [core] example - Camera View
* Example complexity rating: [] 4/4
*
* Example originally created with raylib 6.0? (target)
*
* Example contributed by IANN (@meisei4) and reviewed by Ramon Santamaria (@raysan5) and community
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025-2025 @meisei4
*
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
#include "rlgl.h"
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
static const char *vert =
"#version 330\n"
"in vec3 vertexPosition;\n"
"in vec2 vertexTexCoord;\n"
"in vec3 vertexNormal;\n"
"in vec4 vertexColor;\n"
"uniform mat4 mvp;\n"
"out vec2 fragTexCoord;\n"
"out vec4 fragColor;\n"
"uniform int useVertexColors;\n"
"void main()\n"
"{\n"
" if (useVertexColors == 1) {\n"
" fragColor = vertexColor;\n"
" } else {\n"
" fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
" }\n"
" fragTexCoord = vertexTexCoord;\n"
" gl_Position = mvp * vec4(vertexPosition, 1.0);\n"
"}\n";
static const char *frag =
"#version 330\n"
"in vec2 fragTexCoord;\n"
"in vec4 fragColor;\n"
"uniform sampler2D texture0;\n"
"uniform vec4 colDiffuse;\n"
"out vec4 finalColor;\n"
"void main()\n"
"{\n"
" vec4 texelColor = texture(texture0, fragTexCoord);\n"
" vec4 outColor = texelColor*fragColor*colDiffuse;\n"
" if (outColor.a <= 0.0) discard; \n"
" finalColor = outColor;\n"
"}\n";
static Shader customShader = { 0 };
static int useVertexColorsLoc = -1;
#define BAHAMA_BLUE CLITERAL(Color){ 0, 102, 153, 255 }
#define SUNFLOWER CLITERAL(Color){ 255, 204, 153, 255 }
#define ANAKIWA CLITERAL(Color){ 153, 204, 255, 255 }
#define MARINER CLITERAL(Color){ 51, 102, 204, 255 }
#define NEON_CARROT CLITERAL(Color){ 255, 153, 51, 255 }
#define EGGPLANT CLITERAL(Color){ 102, 68, 102, 255 }
#define HOPBUSH CLITERAL(Color){ 204, 102, 153, 255 }
#define LILAC CLITERAL(Color){ 204, 153, 204, 255 }
#define RED_DAMASK CLITERAL(Color){ 221, 102, 68, 255 }
#define CHESTNUT_ROSE CLITERAL(Color){ 204, 102, 102, 255 }
typedef unsigned short Triangle[3];
enum Flags
{
FLAG_ASPECT = 1u<<0,
FLAG_PAUSE = 1u<<1,
FLAG_JUGEMU = 1u<<2,
FLAG_ORTHO = 1u<<3,
GEN_CUBE = 1u<<4,
GEN_SPHERE = 1u<<5,
GEN_KNOT = 1u<<6
};
static unsigned int gflags = FLAG_ASPECT | FLAG_JUGEMU | GEN_CUBE;
#define ASPECT_CORRECT() ((gflags & FLAG_ASPECT) != 0)
#define PAUSED() ((gflags & FLAG_PAUSE) != 0)
#define JUGEMU_MODE() ((gflags & FLAG_JUGEMU) != 0)
#define ORTHO_MODE() ((gflags & FLAG_ORTHO) != 0)
#define TOGGLE(K, F) do { if (IsKeyPressed(K)) { gflags ^= (F); } } while (0)
static unsigned int targetMesh = 0;
#define NUM_MODELS 3
#define CYCLE_MESH(K, I, F) do { if (IsKeyPressed(K)) { targetMesh = (I); gflags = (gflags & ~(GEN_CUBE|GEN_SPHERE|GEN_KNOT)) | (F); } } while (0)
static int fontSize = 20;
static float angularVelocity = 1.25f;
static float fovyPerspective = 60.0f;
static float nearPlaneHeightOrthographic = 1.0f;
static float blendScalar = 5.0f;
static Vector3 yAxis = { 0.0f, 1.0f, 0.0f };
static Vector3 modelPos = { 0.0f, 0.0f, 0.0f };
static Vector3 modelScale = { 1.0f, 1.0f, 1.0f };
static Vector3 mainPos = { 0.0f, 0.0f, 2.0f };
static Vector3 jugemuPosIso = { 3.0f, 1.0f, 3.0f };
static void UpdateSpatialFrame(Camera3D *main, float aspect, float near, float far, Mesh *spatialFrame);
static void DrawSpatialFrame(Mesh *spatialFrame);
static void PerspectiveCorrectCapture(Camera3D *main, Model *model, RenderTexture2D *perspectiveCorrectRenderTexture, float rotation);
static void FillVertexColors(Mesh *mesh);
static void OrbitSpace(Camera3D *jugemu, float dt);
static Vector3 TranslateRotateScale(Vector3 coordinate, Vector3 pos, Vector3 scale, float rotation);
static Vector3 Intersect(Camera3D *main, float near, Vector3 worldCoord);
static float OrthoBlendFactor(float dt);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - fixed function didactic");
customShader = LoadShaderFromMemory(vert, frag);
useVertexColorsLoc = GetShaderLocation(customShader, "useVertexColors");
RenderTexture2D perspectiveCorrectRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
float near = 1.0f;
float far = 3.0f;
float aspect = (float)GetScreenWidth()/(float)GetScreenHeight();
nearPlaneHeightOrthographic = 2.0f*near*tanf(DEG2RAD*fovyPerspective*0.5f);
float meshRotation = 0.0f;
Camera3D main = { 0 };
main.position = mainPos;
main.target = modelPos;
main.up = yAxis;
main.projection = (ORTHO_MODE())? CAMERA_ORTHOGRAPHIC : CAMERA_PERSPECTIVE;
main.fovy = (ORTHO_MODE())? nearPlaneHeightOrthographic: fovyPerspective;
Camera3D jugemu = (Camera3D){ 0 };
jugemu.position = jugemuPosIso;
jugemu.target = modelPos;
jugemu.up = yAxis;
jugemu.fovy = fovyPerspective;
jugemu.projection = CAMERA_PERSPECTIVE;
Model models[NUM_MODELS] = { 0 };
models[0] = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
models[1] = LoadModelFromMesh(GenMeshSphere(0.5f, 8, 8));
models[2] = LoadModelFromMesh(GenMeshKnot(1.0f, 1.0f, 16, 128));
for (int i = 0; i < NUM_MODELS; i++)
{
Mesh *mesh = &models[i].meshes[0];
mesh->vaoId = 0;
if (!mesh->indices)
{
mesh->indices = RL_CALLOC(mesh->vertexCount, sizeof(unsigned short));
for (int j = 0; j < mesh->vertexCount; j++) mesh->indices[j] = (unsigned short)j;
mesh->triangleCount = mesh->vertexCount/3;
}
FillVertexColors(mesh);
UploadMesh(mesh, true);
}
Mesh tempCube = GenMeshCube(1.0f, 1.0f, 1.0f);
Mesh spatialFrame = { 0 };
spatialFrame.vertexCount = tempCube.vertexCount;
spatialFrame.triangleCount = tempCube.triangleCount;
spatialFrame.vertices = RL_MALLOC(spatialFrame.vertexCount * 3 * sizeof(float));
spatialFrame.normals = RL_MALLOC(spatialFrame.vertexCount * 3 * sizeof(float));
spatialFrame.texcoords = RL_MALLOC(spatialFrame.vertexCount * 2 * sizeof(float));
spatialFrame.indices = RL_MALLOC(spatialFrame.triangleCount * 3 * sizeof(unsigned short));
spatialFrame.colors = RL_CALLOC(spatialFrame.vertexCount, sizeof(Color));
memcpy(spatialFrame.vertices, tempCube.vertices, spatialFrame.vertexCount * 3 * sizeof(float));
memcpy(spatialFrame.normals, tempCube.normals, spatialFrame.vertexCount * 3 * sizeof(float));
memcpy(spatialFrame.texcoords, tempCube.texcoords, spatialFrame.vertexCount * 2 * sizeof(float));
memcpy(spatialFrame.indices, tempCube.indices, spatialFrame.triangleCount * 3 * sizeof(unsigned short));
for (int i = 0; i < spatialFrame.vertexCount; i++) ((Color *)spatialFrame.colors)[i] = (Color){ 255, 255, 255, 0 };
for (int i = 0; i < 4; i++) ((Color *)spatialFrame.colors)[i].a = 255;
UnloadMesh(tempCube);
UploadMesh(&spatialFrame, true);
Model spatialFrameModel = LoadModelFromMesh(spatialFrame);
spatialFrameModel.materials[0].shader = customShader;
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
while (!WindowShouldClose())
{
// Update
//----------------------------------------------------------------------------------
aspect = (float)GetScreenWidth()/(float)GetScreenHeight();
TOGGLE(KEY_Q, FLAG_ASPECT);
TOGGLE(KEY_SPACE, FLAG_PAUSE);
TOGGLE(KEY_J, FLAG_JUGEMU);
TOGGLE(KEY_O, FLAG_ORTHO);
CYCLE_MESH(KEY_ONE, 0, GEN_CUBE);
CYCLE_MESH(KEY_TWO, 1, GEN_SPHERE);
CYCLE_MESH(KEY_THREE, 2, GEN_KNOT);
OrthoBlendFactor(GetFrameTime());
if (!PAUSED()) meshRotation -= angularVelocity*GetFrameTime();
OrbitSpace(&jugemu, GetFrameTime());
main.projection = (ORTHO_MODE())? CAMERA_ORTHOGRAPHIC : CAMERA_PERSPECTIVE;
main.fovy = (ORTHO_MODE())? nearPlaneHeightOrthographic : fovyPerspective;
Model *displayModel = &models[targetMesh];
PerspectiveCorrectCapture(&main, displayModel, &perspectiveCorrectRenderTexture, meshRotation);
UpdateSpatialFrame(&main, aspect, near, far, &spatialFrame);
UpdateMeshBuffer(spatialFrameModel.meshes[0], RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, spatialFrame.vertices, spatialFrame.vertexCount*sizeof(Vector3), 0);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(BLACK);
if (JUGEMU_MODE()) BeginMode3D(jugemu); else BeginMode3D(main);
Vector3 depth = Vector3Normalize(Vector3Subtract(main.target, main.position));
Vector3 right = Vector3Normalize(Vector3CrossProduct(depth, main.up));
Vector3 up = Vector3Normalize(Vector3CrossProduct(right, depth));
DrawLine3D(main.position, Vector3Add(main.position, right), NEON_CARROT);
DrawLine3D(main.position, Vector3Add(main.position, up), LILAC);
DrawLine3D(main.position, Vector3Add(main.position, depth), MARINER);
if (JUGEMU_MODE()) DrawSpatialFrame(&spatialFrame);
DrawModelEx(*displayModel, modelPos, yAxis, RAD2DEG*meshRotation, modelScale, WHITE);
unsigned int cacheID = displayModel->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id;
displayModel->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = rlGetTextureIdDefault();
DrawModelWiresEx(*displayModel, modelPos, yAxis, RAD2DEG*meshRotation, modelScale, MARINER);
rlSetPointSize(4.0f);
DrawModelPointsEx(*displayModel, modelPos, yAxis, RAD2DEG*meshRotation, modelScale, LILAC);
displayModel->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = cacheID;
if (JUGEMU_MODE())
{
Vector3 *vertices = (Vector3 *)displayModel->meshes[0].vertices;
Triangle *triangles = (Triangle *)displayModel->meshes[0].indices;
for (int i = 0; i < displayModel->meshes[0].triangleCount; i++)
{
Vector3 a = TranslateRotateScale(vertices[triangles[i][0]], modelPos, modelScale, meshRotation);
Vector3 b = TranslateRotateScale(vertices[triangles[i][1]], modelPos, modelScale, meshRotation);
Vector3 c = TranslateRotateScale(vertices[triangles[i][2]], modelPos, modelScale, meshRotation);
if (Vector3DotProduct(Vector3Normalize(Vector3CrossProduct(Vector3Subtract(b, a), Vector3Subtract(c, a))), depth) > 0.0f) continue;
DrawLine3D(a, Intersect(&main, near, a), (Color){ RED_DAMASK.r, RED_DAMASK.g, RED_DAMASK.b, 20 });
DrawLine3D(b, Intersect(&main, near, b), (Color){ RED_DAMASK.r, RED_DAMASK.g, RED_DAMASK.b, 20 });
DrawLine3D(c, Intersect(&main, near, c), (Color){ RED_DAMASK.r, RED_DAMASK.g, RED_DAMASK.b, 20 });
}
}
spatialFrameModel.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = perspectiveCorrectRenderTexture.texture;
//NOTE: there is still the alpha threshold issue without custom frag shader...
int useColors = 1;
SetShaderValue(spatialFrameModel.materials[0].shader, useVertexColorsLoc, &useColors, SHADER_UNIFORM_INT);
if (JUGEMU_MODE()) DrawModel(spatialFrameModel, modelPos, 1.0f, WHITE);
EndMode3D();
DrawText("[1]: CUBE [2]: SPHERE [3]: KNOT", 12, 12, fontSize, NEON_CARROT);
DrawText("ARROWS: MOVE | SPACEBAR: PAUSE", 12, 38, fontSize, NEON_CARROT);
DrawText("W S : ZOOM ", 12, 64, fontSize, NEON_CARROT);
DrawText((targetMesh == 0)? "GEN_CUBE" : (targetMesh == 1)? "GEN_SPHERE" : "GEN_KNOT", 12, 205, fontSize, NEON_CARROT);
DrawText("ASPECT [ Q ]:", 12, 392, fontSize, SUNFLOWER);
DrawText((ASPECT_CORRECT())? "CORRECT" : "INCORRECT", 230, 392, fontSize, (ASPECT_CORRECT())? ANAKIWA : CHESTNUT_ROSE);
DrawText("LENS [ O ]:", 510, 366, fontSize, SUNFLOWER);
DrawText((ORTHO_MODE())? "ORTHOGRAPHIC" : "PERSPECTIVE", 630, 366, fontSize, (ORTHO_MODE())? BAHAMA_BLUE : ANAKIWA);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadModel(models[0]);
UnloadModel(models[1]);
UnloadModel(models[2]);
UnloadModel(spatialFrameModel);
if (perspectiveCorrectRenderTexture.id) UnloadRenderTexture(perspectiveCorrectRenderTexture);
UnloadShader(customShader);
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}
static void UpdateSpatialFrame(Camera3D *main, float aspect, float near, float far, Mesh *spatialFrame)
{
Vector3 depth = Vector3Normalize(Vector3Subtract(main->target, main->position));
Vector3 right = Vector3Normalize(Vector3CrossProduct(depth, main->up));
Vector3 up = Vector3Normalize(Vector3CrossProduct(right, depth));
float halfHNear = Lerp(near*tanf(DEG2RAD*fovyPerspective*0.5f), 0.5f*nearPlaneHeightOrthographic, OrthoBlendFactor(0.0f));
float halfWNear = halfHNear*aspect;
float halfHFar = Lerp(far*tanf(DEG2RAD*fovyPerspective*0.5f), 0.5f*nearPlaneHeightOrthographic, OrthoBlendFactor(0.0f));
float halfWFar = halfHFar*aspect;
float halfDepth = 0.5f*(far - near);
Vector3 centerNear = Vector3Add(main->position, Vector3Scale(depth, near));
for (int i = 0; i < spatialFrame->vertexCount; ++i)
{
Vector3 offset = Vector3Subtract(((Vector3 *)spatialFrame->vertices)[i], centerNear);
float xSign = (Vector3DotProduct(offset, right) >= 0.0f)? 1.0f : -1.0f;
float ySign = (Vector3DotProduct(offset, up) >= 0.0f)? 1.0f : -1.0f;
float farMask = (Vector3DotProduct(offset, depth) > halfDepth)? 1.0f : 0.0f;
float finalHalfW = halfWNear + farMask*(halfWFar - halfWNear);
float finalHalfH = halfHNear + farMask*(halfHFar - halfHNear);
Vector3 center = Vector3Add(centerNear, Vector3Scale(depth, farMask*2.0f*halfDepth));
((Vector3 *)spatialFrame->vertices)[i] = Vector3Add(center, Vector3Add(Vector3Scale(right, xSign*finalHalfW), Vector3Scale(up, ySign*finalHalfH)));
}
}
static void DrawSpatialFrame(Mesh *spatialFrame)
{
static int frontFaces[4][2] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 } };
static int backFaces[4][2] = { { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 } };
static int ribFaces[4][2] = { { 0, 4 }, { 1, 7 }, { 2, 6 }, { 3, 5 } };
static int (*faces[3])[2] = { frontFaces, backFaces, ribFaces };
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; j++)
{
Vector3 startPosition = ((Vector3 *)spatialFrame->vertices)[faces[i][j][0]];
Vector3 endPosition = ((Vector3 *)spatialFrame->vertices)[faces[i][j][1]];
DrawLine3D(startPosition, endPosition, (i == 0)? NEON_CARROT : (i == 1)? EGGPLANT : HOPBUSH);
}
}
static void PerspectiveCorrectCapture(Camera3D *main, Model *model, RenderTexture2D *perspectiveCorrectRenderTexture, float rotation)
{
BeginTextureMode(*perspectiveCorrectRenderTexture);
ClearBackground(BLANK);
BeginMode3D(*main);
DrawModelEx(*model, modelPos, yAxis, RAD2DEG*rotation, modelScale, WHITE);
DrawModelWiresEx(*model, modelPos, yAxis, RAD2DEG*rotation, modelScale, MARINER);
EndMode3D();
EndTextureMode();
}
static void OrbitSpace(Camera3D *jugemu, float dt)
{
float radius = Vector3Length(jugemu->position);
float azimuth = atan2f(jugemu->position.z, jugemu->position.x);
float horizontalRadius = sqrtf(jugemu->position.x*jugemu->position.x + jugemu->position.z*jugemu->position.z);
float elevation = atan2f(jugemu->position.y, horizontalRadius);
if (IsKeyDown(KEY_LEFT)) azimuth += 1.0f*dt;
if (IsKeyDown(KEY_RIGHT)) azimuth -= 1.0f*dt;
if (IsKeyDown(KEY_UP)) elevation += 1.0f*dt;
if (IsKeyDown(KEY_DOWN)) elevation -= 1.0f*dt;
if (IsKeyDown(KEY_W)) radius -= 1.0f*dt;
if (IsKeyDown(KEY_S)) radius += 1.0f*dt;
elevation = Clamp(elevation, -PI/2 + 0.1f, PI/2 - 0.1f);
jugemu->position.x = Clamp(radius, 0.25f, 10.0f)*cosf(elevation)*cosf(azimuth);
jugemu->position.y = Clamp(radius, 0.25f, 10.0f)*sinf(elevation);
jugemu->position.z = Clamp(radius, 0.25f, 10.0f)*cosf(elevation)*sinf(azimuth);
}
static void FillVertexColors(Mesh *mesh)
{
if (!mesh->colors) mesh->colors = RL_CALLOC(mesh->vertexCount, sizeof(Color));
Color *colors = (Color *)mesh->colors;
Vector3 *vertices = (Vector3 *)mesh->vertices;
BoundingBox bounds = GetMeshBoundingBox(*mesh);
for (int i = 0; i < mesh->vertexCount; ++i)
{
Vector3 vertex = vertices[i];
float nx = (vertex.x - 0.5f*(bounds.min.x + bounds.max.x))/(0.5f*(bounds.max.x - bounds.min.x));
float ny = (vertex.y - 0.5f*(bounds.min.y + bounds.max.y))/(0.5f*(bounds.max.y - bounds.min.y));
float nz = (vertex.z - 0.5f*(bounds.min.z + bounds.max.z))/(0.5f*(bounds.max.z - bounds.min.z));
float len = sqrtf(nx*nx + ny*ny + nz*nz);
colors[i] = (Color){ lrintf(127.5f*(nx/len + 1.0f)), lrintf(127.5f*(ny/len + 1.0f)), lrintf(127.5f*(nz/len + 1.0f)), 255 };
}
}
static Vector3 TranslateRotateScale(Vector3 coordinate, Vector3 pos, Vector3 scale, float rotation)
{
return Vector3Transform(coordinate, MatrixMultiply(MatrixMultiply(MatrixScale(scale.x, scale.y, scale.z), MatrixRotateY(rotation)), MatrixTranslate(pos.x, pos.y, pos.z)));
}
static Vector3 Intersect(Camera3D *main, float near, Vector3 worldCoord)
{
Vector3 viewDir = Vector3Normalize(Vector3Subtract(main->target, main->position));
Vector3 mainCameraToPoint = Vector3Subtract(worldCoord, main->position);
float depthAlongView = Vector3DotProduct(mainCameraToPoint, viewDir);
Vector3 centerNearPlane = Vector3Add(main->position, Vector3Scale(viewDir, near));
if (depthAlongView <= 0.0f) return centerNearPlane;
float scaleToNear = near/depthAlongView;
Vector3 resultPerspective = Vector3Add(main->position, Vector3Scale(mainCameraToPoint, scaleToNear));
Vector3 resultOrtho = Vector3Add(worldCoord, Vector3Scale(viewDir, Vector3DotProduct(Vector3Subtract(centerNearPlane, worldCoord), viewDir)));
return Vector3Lerp(resultPerspective, resultOrtho, OrthoBlendFactor(0.0f));
}
static float OrthoBlendFactor(float dt)
{
static float blend = 0.0f;
if (dt > 0.0f) blend = Clamp(blend + ((ORTHO_MODE())? 1.0f : -1.0f)*blendScalar*dt, 0.0f, 1.0f);
return blend;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -35,6 +35,49 @@
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#if defined(GRAPHICS_API_OPENGL_33)
static const char *vert =
"#version 330\n"
"in vec3 vertexPosition;\n"
"in vec2 vertexTexCoord;\n"
"in vec3 vertexNormal;\n"
"in vec4 vertexColor;\n"
"uniform mat4 mvp;\n"
"out vec2 fragTexCoord;\n"
"out vec4 fragColor;\n"
"uniform int useVertexColors;\n"
"uniform int flipTexcoordY;\n"
"void main()\n"
"{\n"
" if (useVertexColors == 1) {\n"
" fragColor = vertexColor;\n"
" } else {\n"
" fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
" }\n"
" fragTexCoord = vec2(vertexTexCoord.x, (flipTexcoordY == 1)? (1.0 - vertexTexCoord.y) : vertexTexCoord.y);\n"
" gl_Position = mvp * vec4(vertexPosition, 1.0);\n"
"}\n";
static const char *frag =
"#version 330\n"
"in vec2 fragTexCoord;\n"
"in vec4 fragColor;\n"
"uniform sampler2D texture0;\n"
"uniform vec4 colDiffuse;\n"
"out vec4 finalColor;\n"
"void main()\n"
"{\n"
" vec4 texelColor = texture(texture0, fragTexCoord);\n"
" vec4 outColor = texelColor*fragColor*colDiffuse;\n"
" if (outColor.a <= 0.0) discard; \n"
" finalColor = outColor;\n"
"}\n";
static Shader customShader = { 0 };
static int useVertexColorsLoc = -1;
static int flipTexcoordYLoc = -1;
#endif
#define BAHAMA_BLUE CLITERAL(Color){ 0, 102, 153, 255 } #define BAHAMA_BLUE CLITERAL(Color){ 0, 102, 153, 255 }
#define SUNFLOWER CLITERAL(Color){ 255, 204, 153, 255 } #define SUNFLOWER CLITERAL(Color){ 255, 204, 153, 255 }
#define PALE_CANARY CLITERAL(Color){ 255, 255, 153, 255 } #define PALE_CANARY CLITERAL(Color){ 255, 255, 153, 255 }
@ -103,15 +146,19 @@ static void WorldToNDCSpace(Camera3D *main, float aspect, float near, float far,
static void DrawModelFilled(Model *model, Texture2D texture, float rotation); static void DrawModelFilled(Model *model, Texture2D texture, float rotation);
static void DrawModelWiresAndPoints(Model *model, float rotation); static void DrawModelWiresAndPoints(Model *model, float rotation);
static void DrawNearPlanePoints(Camera3D *main, float aspect, float near, Model *nearPlanePointsModel, Mesh *mesh, float rotation); static void DrawNearPlanePoints(Camera3D *main, float aspect, float near, Model *nearPlanePointsModel, Model *displayModel, float rotation);
static void UpdateSpatialFrame(Camera3D *main, float aspect, float near, float far, Mesh *spatialFrame); static void UpdateSpatialFrame(Camera3D *main, float aspect, float near, float far, Mesh *spatialFrame);
static void DrawSpatialFrame(Mesh *spatialFrame); static void DrawSpatialFrame(Mesh *spatialFrame);
static void PerspectiveIncorrectCapture(Camera3D *main, float aspect, float near, Mesh *mesh, Texture2D meshTexture, float rotation); static void PerspectiveIncorrectCapture(Camera3D *main, float aspect, float near, Model *displayModel, Texture2D meshTexture, float rotation);
#if defined(GRAPHICS_API_OPENGL_33)
static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D meshTexture, RenderTexture2D *perspectiveCorrectRenderTexture, float rotation);
#else
static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D meshTexture, Texture2D *perspectiveCorrectTexture, float rotation); static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D meshTexture, Texture2D *perspectiveCorrectTexture, float rotation);
#endif
static void AlphaMaskPunchOut(Image *rgba, Image *mask, unsigned char threshold); static void AlphaMaskPunchOut(Image *rgba, Image *mask, unsigned char threshold);
static void FillPlanarTexCoords(Mesh *mesh);
static void FillVertexColors(Mesh *mesh); static void FillVertexColors(Mesh *mesh);
static void OrbitSpace(Camera3D *jugemu, float dt); static void OrbitSpace(Camera3D *jugemu, float dt);
static Vector3 AspectCorrectAndReflectNearPlane(Vector3 intersect, Vector3 center, Vector3 right, Vector3 up, float xAspect, float yReflect); static Vector3 AspectCorrectAndReflectNearPlane(Vector3 intersect, Vector3 center, Vector3 right, Vector3 up, float xAspect, float yReflect);
@ -133,6 +180,14 @@ int main(void)
const int screenHeight = 450; const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - fixed function didactic"); InitWindow(screenWidth, screenHeight, "raylib [core] example - fixed function didactic");
#if defined(GRAPHICS_API_OPENGL_33)
customShader = LoadShaderFromMemory(vert, frag);
useVertexColorsLoc = GetShaderLocation(customShader, "useVertexColors");
flipTexcoordYLoc = GetShaderLocation(customShader, "flipTexcoordY");
RenderTexture2D perspectiveCorrectRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
#else
Texture2D perspectiveCorrectTexture = (Texture2D){ 0 };
#endif
float near = 1.0f; float near = 1.0f;
float far = 3.0f; float far = 3.0f;
float aspect = (float)GetScreenWidth()/(float)GetScreenHeight(); float aspect = (float)GetScreenWidth()/(float)GetScreenHeight();
@ -168,27 +223,13 @@ int main(void)
if (i == 4) worldModels[4] = LoadModelFromMesh(GenMeshKnot(1.0f, 1.0f, 16, 128)); if (i == 4) worldModels[4] = LoadModelFromMesh(GenMeshKnot(1.0f, 1.0f, 16, 128));
Mesh *worldMesh = &worldModels[i].meshes[0]; Mesh *worldMesh = &worldModels[i].meshes[0];
if (!worldMesh->indices) if (!worldMesh->indices)
{ {
worldMesh->indices = RL_CALLOC(worldMesh->vertexCount, sizeof(unsigned short)); worldMesh->indices = RL_CALLOC(worldMesh->vertexCount, sizeof(unsigned short));
for (int j = 0; j < worldMesh->vertexCount; j++) worldMesh->indices[j] = (unsigned short)j; for (int j = 0; j < worldMesh->vertexCount; j++) worldMesh->indices[j] = (unsigned short)j;
worldMesh->triangleCount = worldMesh->vertexCount/3; worldMesh->triangleCount = worldMesh->vertexCount/3;
} }
if (!worldMesh->texcoords) FillPlanarTexCoords(worldMesh);
{
worldMesh->texcoords = (float *)RL_CALLOC(worldMesh->vertexCount, sizeof(Vector2));
// Demonstrate planar mapping ("reasonable" default): https://en.wikipedia.org/wiki/Planar_projection.
BoundingBox bounds = GetMeshBoundingBox(*worldMesh);
Vector3 extents = Vector3Subtract(bounds.max, bounds.min);
for (int j = 0; j < worldMesh->vertexCount; j++)
{
float x = ((Vector3 *)worldMesh->vertices)[j].x;
float y = ((Vector3 *)worldMesh->vertices)[j].y;
((Vector2 *)worldMesh->texcoords)[j].x = (x - bounds.min.x)/extents.x;
((Vector2 *)worldMesh->texcoords)[j].y = (y - bounds.min.y)/extents.y;
}
}
FillVertexColors(worldMesh); FillVertexColors(worldMesh);
Image textureImage = GenImageChecked(textureConfig[i], textureConfig[i], 1, 1, BLACK, WHITE); Image textureImage = GenImageChecked(textureConfig[i], textureConfig[i], 1, 1, BLACK, WHITE);
@ -207,22 +248,42 @@ int main(void)
if (worldMesh->texcoords) memcpy(ndcMesh.texcoords, worldMesh->texcoords, ndcMesh.vertexCount*sizeof(Vector2)); if (worldMesh->texcoords) memcpy(ndcMesh.texcoords, worldMesh->texcoords, ndcMesh.vertexCount*sizeof(Vector2));
if (worldMesh->colors) ndcMesh.colors = RL_CALLOC(ndcMesh.vertexCount, sizeof(Color)); if (worldMesh->colors) ndcMesh.colors = RL_CALLOC(ndcMesh.vertexCount, sizeof(Color));
if (worldMesh->colors) memcpy(ndcMesh.colors, worldMesh->colors, ndcMesh.vertexCount*sizeof(Color)); if (worldMesh->colors) memcpy(ndcMesh.colors, worldMesh->colors, ndcMesh.vertexCount*sizeof(Color));
UploadMesh(&ndcMesh, true); //this allows for UpdateMeshBuffer later on, but its rought just to work around genmesh upload being static
ndcModels[i] = LoadModelFromMesh(ndcMesh); ndcModels[i] = LoadModelFromMesh(ndcMesh);
ndcModels[i].materials[0].maps[MATERIAL_MAP_ALBEDO].texture = meshTextures[i]; ndcModels[i].materials[0].maps[MATERIAL_MAP_ALBEDO].texture = meshTextures[i];
#if defined(GRAPHICS_API_OPENGL_33)
worldModels[i].materials[0].shader = customShader;
ndcModels[i].materials[0].shader = customShader;
#endif
Mesh nearPlanePoints = (Mesh){ 0 }; Mesh nearPlanePoints = (Mesh){ 0 };
nearPlanePoints.vertexCount = worldMesh->triangleCount*3; nearPlanePoints.vertexCount = worldMesh->triangleCount*3;
nearPlanePoints.vertices = RL_CALLOC(nearPlanePoints.vertexCount, sizeof(Vector3)); nearPlanePoints.vertices = RL_CALLOC(nearPlanePoints.vertexCount, sizeof(Vector3));
UploadMesh(&nearPlanePoints, true);
nearPlanePointsModels[i] = LoadModelFromMesh(nearPlanePoints); nearPlanePointsModels[i] = LoadModelFromMesh(nearPlanePoints);
} }
Texture2D perspectiveCorrectTexture = (Texture2D){ 0 }; Mesh tempCube = GenMeshCube(1.0f, 1.0f, 1.0f);
Mesh spatialFrame = GenMeshCube(1.0f, 1.0f, 1.0f); Mesh spatialFrame = { 0 };
spatialFrame.vertexCount = tempCube.vertexCount;
spatialFrame.triangleCount = tempCube.triangleCount;
spatialFrame.vertices = RL_MALLOC(spatialFrame.vertexCount * 3 * sizeof(float));
spatialFrame.normals = RL_MALLOC(spatialFrame.vertexCount * 3 * sizeof(float));
spatialFrame.texcoords = RL_MALLOC(spatialFrame.vertexCount * 2 * sizeof(float));
spatialFrame.indices = RL_MALLOC(spatialFrame.triangleCount * 3 * sizeof(unsigned short));
spatialFrame.colors = RL_CALLOC(spatialFrame.vertexCount, sizeof(Color)); spatialFrame.colors = RL_CALLOC(spatialFrame.vertexCount, sizeof(Color));
memcpy(spatialFrame.vertices, tempCube.vertices, spatialFrame.vertexCount * 3 * sizeof(float));
memcpy(spatialFrame.normals, tempCube.normals, spatialFrame.vertexCount * 3 * sizeof(float));
memcpy(spatialFrame.texcoords, tempCube.texcoords, spatialFrame.vertexCount * 2 * sizeof(float));
memcpy(spatialFrame.indices, tempCube.indices, spatialFrame.triangleCount * 3 * sizeof(unsigned short));
for (int i = 0; i < spatialFrame.vertexCount; i++) ((Color *)spatialFrame.colors)[i] = (Color){ 255, 255, 255, 0 }; for (int i = 0; i < spatialFrame.vertexCount; i++) ((Color *)spatialFrame.colors)[i] = (Color){ 255, 255, 255, 0 };
for (int i = 0; i < 4; i++) ((Color *)spatialFrame.colors)[i].a = 255; for (int i = 0; i < 4; i++) ((Color *)spatialFrame.colors)[i].a = 255;
UnloadMesh(tempCube); //NOTE: to clean up static mesh -- better would be to allow for gen mesh to have option for dynamic or static
UploadMesh(&spatialFrame, true);
Model spatialFrameModel = LoadModelFromMesh(spatialFrame); Model spatialFrameModel = LoadModelFromMesh(spatialFrame);
#if defined(GRAPHICS_API_OPENGL_33)
spatialFrameModel.materials[0].shader = customShader;
#endif
SetTargetFPS(60); SetTargetFPS(60);
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
@ -268,15 +329,20 @@ int main(void)
ndcVertices[i].z = Lerp(worldVertices[i].z, ndcVertices[i].z, sBlend); ndcVertices[i].z = Lerp(worldVertices[i].z, ndcVertices[i].z, sBlend);
} }
UpdateMeshBuffer(ndcModels[targetMesh].meshes[0], RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, ndcModels[targetMesh].meshes[0].vertices, ndcModels[targetMesh].meshes[0].vertexCount*sizeof(Vector3), 0);
Model *displayModel = &ndcModels[targetMesh]; Model *displayModel = &ndcModels[targetMesh];
Mesh *displayMesh = &ndcModels[targetMesh].meshes[0];
if (PERSPECTIVE_CORRECT() && TEXTURE_MODE()) if (PERSPECTIVE_CORRECT() && TEXTURE_MODE())
{ {
#if defined(GRAPHICS_API_OPENGL_33)
PerspectiveCorrectCapture(&main, displayModel, meshTextures[targetMesh], &perspectiveCorrectRenderTexture, meshRotation);
#else
PerspectiveCorrectCapture(&main, displayModel, meshTextures[targetMesh], &perspectiveCorrectTexture, meshRotation); PerspectiveCorrectCapture(&main, displayModel, meshTextures[targetMesh], &perspectiveCorrectTexture, meshRotation);
#endif
} }
UpdateSpatialFrame(&main, aspect, near, far, &spatialFrame); UpdateSpatialFrame(&main, aspect, near, far, &spatialFrame);
UpdateMeshBuffer(spatialFrameModel.meshes[0], RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, spatialFrame.vertices, spatialFrame.vertexCount*sizeof(Vector3), 0);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Draw // Draw
@ -297,16 +363,29 @@ int main(void)
DrawModelFilled(displayModel, meshTextures[targetMesh], meshRotation); DrawModelFilled(displayModel, meshTextures[targetMesh], meshRotation);
DrawModelWiresAndPoints(displayModel, meshRotation); DrawModelWiresAndPoints(displayModel, meshRotation);
if (JUGEMU_MODE()) DrawNearPlanePoints(&main, aspect, near, &nearPlanePointsModels[targetMesh], displayMesh, meshRotation); if (JUGEMU_MODE()) DrawNearPlanePoints(&main, aspect, near, &nearPlanePointsModels[targetMesh], displayModel, meshRotation);
if (PERSPECTIVE_CORRECT() && TEXTURE_MODE()) if (PERSPECTIVE_CORRECT() && TEXTURE_MODE())
{ {
#if defined(GRAPHICS_API_OPENGL_33)
spatialFrameModel.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = perspectiveCorrectRenderTexture.texture;
int useColors = 1;
SetShaderValue(spatialFrameModel.materials[0].shader, useVertexColorsLoc, &useColors, SHADER_UNIFORM_INT);
int flipTexcoordYValue = (NDC_SPACE() && REFLECT_Y())? 1 : 0;
SetShaderValue(spatialFrameModel.materials[0].shader, flipTexcoordYLoc, &flipTexcoordYValue, SHADER_UNIFORM_INT);
if (JUGEMU_MODE()) DrawModel(spatialFrameModel, modelPos, 1.0f, WHITE);
flipTexcoordYValue = 0;
SetShaderValue(spatialFrameModel.materials[0].shader, flipTexcoordYLoc, &flipTexcoordYValue, SHADER_UNIFORM_INT);
#else
spatialFrameModel.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = perspectiveCorrectTexture; spatialFrameModel.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = perspectiveCorrectTexture;
if (JUGEMU_MODE()) DrawModel(spatialFrameModel, modelPos, 1.0f, WHITE); if (JUGEMU_MODE()) DrawModel(spatialFrameModel, modelPos, 1.0f, WHITE);
#endif
} }
else else
{ {
if (JUGEMU_MODE()) PerspectiveIncorrectCapture(&main, aspect, near, displayMesh, meshTextures[targetMesh], meshRotation); if (JUGEMU_MODE()) PerspectiveIncorrectCapture(&main, aspect, near, displayModel, meshTextures[targetMesh], meshRotation);
} }
EndMode3D(); EndMode3D();
@ -348,7 +427,10 @@ int main(void)
if (meshTextures[i].id) UnloadTexture(meshTextures[i]); if (meshTextures[i].id) UnloadTexture(meshTextures[i]);
} }
UnloadModel(spatialFrameModel); UnloadModel(spatialFrameModel);
#if defined(GRAPHICS_API_OPENGL_33)
if (perspectiveCorrectRenderTexture.id) UnloadRenderTexture(perspectiveCorrectRenderTexture);
UnloadShader(customShader);
#endif
CloseWindow(); // Close window and OpenGL context CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
@ -396,27 +478,42 @@ static void WorldToNDCSpace(Camera3D *main, float aspect, float near, float far,
static void DrawModelFilled(Model *model, Texture2D texture, float rotation) static void DrawModelFilled(Model *model, Texture2D texture, float rotation)
{ {
if (!(COLOR_MODE() || TEXTURE_MODE())) return; if (!(COLOR_MODE() || TEXTURE_MODE())) return;
#if defined(GRAPHICS_API_OPENGL_33)
int useColors = COLOR_MODE() ? 1 : 0;
SetShaderValue(model->materials[0].shader, useVertexColorsLoc, &useColors, SHADER_UNIFORM_INT);
#else
Color *cacheColors = (Color *)model->meshes[0].colors; Color *cacheColors = (Color *)model->meshes[0].colors;
if (TEXTURE_MODE() && !COLOR_MODE()) model->meshes[0].colors = NULL; if (TEXTURE_MODE() && !COLOR_MODE()) model->meshes[0].colors = NULL;
model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = (TEXTURE_MODE())? texture.id : 0; #endif
model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = (TEXTURE_MODE())? texture.id : rlGetTextureIdDefault();
DrawModelEx(*model, modelPos, yAxis, RAD2DEG*rotation, modelScale, WHITE); DrawModelEx(*model, modelPos, yAxis, RAD2DEG*rotation, modelScale, WHITE);
model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = 0; model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = rlGetTextureIdDefault();
#if defined(GRAPHICS_API_OPENGL_11)
model->meshes[0].colors = (unsigned char *)cacheColors; model->meshes[0].colors = (unsigned char *)cacheColors;
#endif
} }
static void DrawModelWiresAndPoints(Model *model, float rotation) static void DrawModelWiresAndPoints(Model *model, float rotation)
{ {
#if defined(GRAPHICS_API_OPENGL_33)
int useColors = (CLIP_MODE())? 1 : 0;
SetShaderValue(model->materials[0].shader, useVertexColorsLoc, &useColors, SHADER_UNIFORM_INT);
#else
Color *cacheColors = (Color *)model->meshes[0].colors; Color *cacheColors = (Color *)model->meshes[0].colors;
unsigned int cacheID = model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id;
if (!CLIP_MODE()) model->meshes[0].colors = NULL; if (!CLIP_MODE()) model->meshes[0].colors = NULL;
model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = 0; #endif
unsigned int cacheID = model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id;
model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = rlGetTextureIdDefault();
DrawModelWiresEx(*model, modelPos, yAxis, RAD2DEG*rotation, modelScale, MARINER); DrawModelWiresEx(*model, modelPos, yAxis, RAD2DEG*rotation, modelScale, MARINER);
rlSetPointSize(4.0f); rlSetPointSize(4.0f);
DrawModelPointsEx(*model, modelPos, yAxis, RAD2DEG*rotation, modelScale, LILAC); DrawModelPointsEx(*model, modelPos, yAxis, RAD2DEG*rotation, modelScale, LILAC);
model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = cacheID; model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture.id = cacheID;
#if defined(GRAPHICS_API_OPENGL_11)
model->meshes[0].colors = (unsigned char *)cacheColors; model->meshes[0].colors = (unsigned char *)cacheColors;
#endif
} }
static void UpdateSpatialFrame(Camera3D *main, float aspect, float near, float far, Mesh *spatialFrame) static void UpdateSpatialFrame(Camera3D *main, float aspect, float near, float far, Mesh *spatialFrame)
@ -462,21 +559,22 @@ static void DrawSpatialFrame(Mesh *spatialFrame)
} }
} }
static void DrawNearPlanePoints(Camera3D *main, float aspect, float near, Model *nearPlanePointsModel, Mesh *mesh, float rotation) static void DrawNearPlanePoints(Camera3D *main, float aspect, float near, Model *nearPlanePointsModel, Model *displayModel, float rotation)
{ {
Vector3 depth, right, up; Vector3 depth, right, up;
BasisVector(main, &depth, &right, &up); BasisVector(main, &depth, &right, &up);
Mesh *displayMesh = &displayModel->meshes[0];
int nearPlaneVertexCount = 0; int nearPlaneVertexCount = 0;
int capacity = mesh->triangleCount*3; int capacity = displayMesh->triangleCount*3;
Mesh *nearPlanePointsMesh = &nearPlanePointsModel->meshes[0]; Mesh *nearPlanePointsMesh = &nearPlanePointsModel->meshes[0];
Vector3 centerNearPlane = Vector3Add(main->position, Vector3Scale(depth, near)); Vector3 centerNearPlane = Vector3Add(main->position, Vector3Scale(depth, near));
float xAspect = Lerp(1.0f/aspect, 1.0f, AspectBlendFactor(0.0f)); float xAspect = Lerp(1.0f/aspect, 1.0f, AspectBlendFactor(0.0f));
float yReflect = Lerp(1.0f, -1.0f, ReflectBlendFactor(0.0f)); float yReflect = Lerp(1.0f, -1.0f, ReflectBlendFactor(0.0f));
for (int i = 0; i < mesh->triangleCount; i++) for (int i = 0; i < displayMesh->triangleCount; i++)
{ {
Vector3 *vertices = (Vector3 *)mesh->vertices; Vector3 *vertices = (Vector3 *)displayMesh->vertices;
Triangle *triangles = (Triangle *)mesh->indices; Triangle *triangles = (Triangle *)displayMesh->indices;
Vector3 a = TranslateRotateScale(0, vertices[triangles[i][0]], modelPos, modelScale, rotation); Vector3 a = TranslateRotateScale(0, vertices[triangles[i][0]], modelPos, modelScale, rotation);
Vector3 b = TranslateRotateScale(0, vertices[triangles[i][1]], modelPos, modelScale, rotation); Vector3 b = TranslateRotateScale(0, vertices[triangles[i][1]], modelPos, modelScale, rotation);
@ -496,24 +594,29 @@ static void DrawNearPlanePoints(Camera3D *main, float aspect, float near, Model
} }
nearPlanePointsMesh->vertexCount = nearPlaneVertexCount; nearPlanePointsMesh->vertexCount = nearPlaneVertexCount;
UpdateMeshBuffer(*nearPlanePointsMesh, RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, nearPlanePointsMesh->vertices, nearPlanePointsMesh->vertexCount*sizeof(Vector3), 0);
rlSetPointSize(3.0f); rlSetPointSize(3.0f);
DrawModelPoints(*nearPlanePointsModel, modelPos, 1.0f, LILAC); DrawModelPoints(*nearPlanePointsModel, modelPos, 1.0f, LILAC);
} }
static void PerspectiveIncorrectCapture(Camera3D *main, float aspect, float near, Mesh *mesh, Texture2D meshTexture, float rotation) static void PerspectiveIncorrectCapture(Camera3D *main, float aspect, float near, Model *displayModel, Texture2D meshTexture, float rotation)
{ {
Vector3 depth, right, up; Vector3 depth, right, up;
BasisVector(main, &depth, &right, &up); BasisVector(main, &depth, &right, &up);
Mesh *displayMesh = &displayModel->meshes[0];
Vector3 centerNearPlane = Vector3Add(main->position, Vector3Scale(depth, near)); Vector3 centerNearPlane = Vector3Add(main->position, Vector3Scale(depth, near));
float xAspect = Lerp(1.0f/aspect, 1.0f, AspectBlendFactor(0.0f)); float xAspect = Lerp(1.0f/aspect, 1.0f, AspectBlendFactor(0.0f));
float yReflect = Lerp(1.0f, -1.0f, ReflectBlendFactor(0.0f)); float yReflect = Lerp(1.0f, -1.0f, ReflectBlendFactor(0.0f));
rlColor4ub(WHITE.r, WHITE.g, WHITE.b, WHITE.a); // just to emphasize raylib Colors are ub 0~255 not floats rlColor4ub(WHITE.r, WHITE.g, WHITE.b, WHITE.a); // just to emphasize raylib Colors are ub 0~255 not floats
if (TEXTURE_MODE() && mesh->texcoords) if (TEXTURE_MODE() && displayMesh->texcoords)
{
rlSetTexture(meshTexture.id);
rlEnableTexture(meshTexture.id); rlEnableTexture(meshTexture.id);
}
else else
{
rlDisableTexture(); rlDisableTexture();
}
if (!TEXTURE_MODE() && !COLOR_MODE()) if (!TEXTURE_MODE() && !COLOR_MODE())
{ {
rlEnableWireMode(); rlEnableWireMode();
@ -521,12 +624,12 @@ static void PerspectiveIncorrectCapture(Camera3D *main, float aspect, float near
} }
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
for (int i = 0; i < mesh->triangleCount; i++) for (int i = 0; i < displayMesh->triangleCount; i++)
{ {
Triangle *triangles = (Triangle *)mesh->indices; Triangle *triangles = (Triangle *)displayMesh->indices;
Vector3 *vertices = (Vector3 *)mesh->vertices; Vector3 *vertices = (Vector3 *)displayMesh->vertices;
Color *colors = (Color *)mesh->colors; Color *colors = (Color *)displayMesh->colors;
Vector2 *texcoords = (Vector2 *)mesh->texcoords; Vector2 *texcoords = (Vector2 *)displayMesh->texcoords;
Vector3 a = TranslateRotateScale(0, vertices[triangles[i][0]], modelPos, modelScale, rotation); Vector3 a = TranslateRotateScale(0, vertices[triangles[i][0]], modelPos, modelScale, rotation);
Vector3 b = TranslateRotateScale(0, vertices[triangles[i][1]], modelPos, modelScale, rotation); Vector3 b = TranslateRotateScale(0, vertices[triangles[i][1]], modelPos, modelScale, rotation);
@ -536,28 +639,46 @@ static void PerspectiveIncorrectCapture(Camera3D *main, float aspect, float near
b = AspectCorrectAndReflectNearPlane(Intersect(main, near, b), centerNearPlane, right, up, xAspect, yReflect); b = AspectCorrectAndReflectNearPlane(Intersect(main, near, b), centerNearPlane, right, up, xAspect, yReflect);
c = AspectCorrectAndReflectNearPlane(Intersect(main, near, c), centerNearPlane, right, up, xAspect, yReflect); c = AspectCorrectAndReflectNearPlane(Intersect(main, near, c), centerNearPlane, right, up, xAspect, yReflect);
if (COLOR_MODE() && mesh->colors) rlColor4ub(colors[triangles[i][0]].r, colors[triangles[i][0]].g, colors[triangles[i][0]].b, colors[triangles[i][0]].a); if (COLOR_MODE() && displayMesh->colors) rlColor4ub(colors[triangles[i][0]].r, colors[triangles[i][0]].g, colors[triangles[i][0]].b, colors[triangles[i][0]].a);
if (TEXTURE_MODE() && mesh->texcoords) rlTexCoord2f(texcoords[triangles[i][0]].x, texcoords[triangles[i][0]].y); if (TEXTURE_MODE() && displayMesh->texcoords) rlTexCoord2f(texcoords[triangles[i][0]].x, texcoords[triangles[i][0]].y);
rlVertex3f(a.x, a.y, a.z); rlVertex3f(a.x, a.y, a.z);
// vertex winding!! to account for reflection toggle (will draw the inside of the geometry otherwise) // vertex winding!! to account for reflection toggle (will draw the inside of the geometry otherwise)
int secondIndex = (NDC_SPACE() && REFLECT_Y())? triangles[i][2] : triangles[i][1]; int secondIndex = (NDC_SPACE() && REFLECT_Y())? triangles[i][2] : triangles[i][1];
Vector3 secondVertex = (NDC_SPACE() && REFLECT_Y())? c : b; Vector3 secondVertex = (NDC_SPACE() && REFLECT_Y())? c : b;
if (COLOR_MODE() && mesh->colors) rlColor4ub(colors[secondIndex].r, colors[secondIndex].g, colors[secondIndex].b, colors[secondIndex].a); if (COLOR_MODE() && displayMesh->colors) rlColor4ub(colors[secondIndex].r, colors[secondIndex].g, colors[secondIndex].b, colors[secondIndex].a);
if (TEXTURE_MODE() && mesh->texcoords) rlTexCoord2f(texcoords[secondIndex].x, texcoords[secondIndex].y); if (TEXTURE_MODE() && displayMesh->texcoords) rlTexCoord2f(texcoords[secondIndex].x, texcoords[secondIndex].y);
rlVertex3f(secondVertex.x, secondVertex.y, secondVertex.z); rlVertex3f(secondVertex.x, secondVertex.y, secondVertex.z);
int thirdIndex = (NDC_SPACE() && REFLECT_Y())? triangles[i][1] : triangles[i][2]; int thirdIndex = (NDC_SPACE() && REFLECT_Y())? triangles[i][1] : triangles[i][2];
Vector3 thirdVertex = (NDC_SPACE() && REFLECT_Y())? b : c; Vector3 thirdVertex = (NDC_SPACE() && REFLECT_Y())? b : c;
if (COLOR_MODE() && mesh->colors) rlColor4ub(colors[thirdIndex].r, colors[thirdIndex].g, colors[thirdIndex].b, colors[thirdIndex].a); if (COLOR_MODE() && displayMesh->colors) rlColor4ub(colors[thirdIndex].r, colors[thirdIndex].g, colors[thirdIndex].b, colors[thirdIndex].a);
if (TEXTURE_MODE() && mesh->texcoords) rlTexCoord2f(texcoords[thirdIndex].x, texcoords[thirdIndex].y); if (TEXTURE_MODE() && displayMesh->texcoords) rlTexCoord2f(texcoords[thirdIndex].x, texcoords[thirdIndex].y);
rlVertex3f(thirdVertex.x, thirdVertex.y, thirdVertex.z); rlVertex3f(thirdVertex.x, thirdVertex.y, thirdVertex.z);
} }
rlEnd(); rlEnd();
rlDrawRenderBatchActive(); //NOTE: this is what allows lines in opengl33
rlSetTexture(rlGetTextureIdDefault());
rlDisableTexture(); rlDisableTexture();
rlDisableWireMode(); rlDisableWireMode();
} }
#if defined(GRAPHICS_API_OPENGL_33)
static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D meshTexture, RenderTexture2D *perspectiveCorrectRenderTexture, float rotation)
{
BeginTextureMode(*perspectiveCorrectRenderTexture);
ClearBackground(BLANK);
BeginMode3D(*main);
int useColors = (COLOR_MODE())? 1 : 0;
SetShaderValue(model->materials[0].shader, useVertexColorsLoc, &useColors, SHADER_UNIFORM_INT);
model->materials[0].maps[MATERIAL_MAP_ALBEDO].texture = meshTexture;
DrawModelEx(*model, modelPos, yAxis, RAD2DEG*rotation, modelScale, WHITE);
EndMode3D();
EndTextureMode();
}
#endif
#if defined(GRAPHICS_API_OPENGL_11)
static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D meshTexture, Texture2D *perspectiveCorrectTexture, float rotation) static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D meshTexture, Texture2D *perspectiveCorrectTexture, float rotation)
{ {
unsigned char *cacheColors = model->meshes[0].colors; unsigned char *cacheColors = model->meshes[0].colors;
@ -575,7 +696,6 @@ static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D me
Image rgba = LoadImageFromScreen(); Image rgba = LoadImageFromScreen();
ImageFormat(&rgba, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); ImageFormat(&rgba, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
model->meshes[0].colors = cacheColors; model->meshes[0].colors = cacheColors;
ClearBackground(BLACK); ClearBackground(BLACK);
BeginMode3D(*main); BeginMode3D(*main);
@ -596,10 +716,10 @@ static void PerspectiveCorrectCapture(Camera3D *main, Model *model, Texture2D me
UpdateTexture(*perspectiveCorrectTexture, rgba.data); UpdateTexture(*perspectiveCorrectTexture, rgba.data);
else else
*perspectiveCorrectTexture = LoadTextureFromImage(rgba); *perspectiveCorrectTexture = LoadTextureFromImage(rgba);
UnloadImage(mask); UnloadImage(mask);
UnloadImage(rgba); UnloadImage(rgba);
} }
#endif
static void OrbitSpace(Camera3D *jugemu, float dt) static void OrbitSpace(Camera3D *jugemu, float dt)
{ {
@ -631,6 +751,26 @@ static void AlphaMaskPunchOut(Image *rgba, Image *mask, unsigned char threshold)
UnloadImage(maskCopy); UnloadImage(maskCopy);
} }
static void FillPlanarTexCoords(Mesh *mesh)
{
//NOTE: opengl33, please just always provide texcoords for the obj, opengl11 allows null because its easy and works with ps2 isolation tests,
// but otherwise they are always assumed to exist
if (!mesh->texcoords)
{
mesh->texcoords = RL_CALLOC(mesh->vertexCount, sizeof(Vector2));
// Demonstrate planar mapping ("reasonable" default): https://en.wikipedia.org/wiki/Planar_projection.
BoundingBox bounds = GetMeshBoundingBox(*mesh);
Vector3 extents = Vector3Subtract(bounds.max, bounds.min);
for (int j = 0; j < mesh->vertexCount; j++)
{
float x = ((Vector3 *)mesh->vertices)[j].x;
float y = ((Vector3 *)mesh->vertices)[j].y;
((Vector2 *)mesh->texcoords)[j].x = (x - bounds.min.x)/extents.x;
((Vector2 *)mesh->texcoords)[j].y = (y - bounds.min.y)/extents.y;
}
}
}
static void FillVertexColors(Mesh *mesh) static void FillVertexColors(Mesh *mesh)
{ {
if (!mesh->colors) mesh->colors = RL_CALLOC(mesh->vertexCount, sizeof(Color)); if (!mesh->colors) mesh->colors = RL_CALLOC(mesh->vertexCount, sizeof(Color));

View File

@ -7,16 +7,21 @@ v -0.5 -0.5 0.5
v 0.5 -0.5 0.5 v 0.5 -0.5 0.5
v 0.5 0.5 0.5 v 0.5 0.5 0.5
v -0.5 0.5 0.5 v -0.5 0.5 0.5
#comment these out to compare opengl11 planar auto fill with just using this and opengl33
vt 0.0 0.0
vt 1.0 0.0
vt 1.0 1.0
vt 0.0 1.0
s off s off
f 1 4 3 f 1/1 4/4 3/3
f 1 3 2 f 1/1 3/3 2/2
f 5 6 7 f 5/1 6/2 7/3
f 5 7 8 f 5/1 7/3 8/4
f 1 5 8 f 1/1 5/1 8/4
f 1 8 4 f 1/1 8/4 4/4
f 2 3 7 f 2/2 3/3 7/3
f 2 7 6 f 2/2 7/3 6/2
f 4 8 7 f 4/4 8/4 7/3
f 4 7 3 f 4/4 7/3 3/3
f 1 2 6 f 1/1 2/2 6/2
f 1 6 5 f 1/1 6/2 5/1