├── .gitignore
├── CMakeLists.txt
├── FindPicoRenderer.cmake
├── LICENSE.txt
├── README.md
├── inc
├── consts.h
├── enums.h
├── error_ids.h
├── pico.h
├── platform.h
├── structs.h
└── types.h
├── src
├── pico.c
├── platform
│ ├── SDL2
│ │ ├── context.c
│ │ └── context.h
│ ├── linux
│ │ ├── context.c
│ │ └── context.h
│ ├── macos
│ │ ├── context.h
│ │ └── context.m
│ └── win32
│ │ ├── context.c
│ │ └── context.h
├── plugins
│ └── stb
│ │ ├── stb_image.h
│ │ └── stb_image_write.h
└── rasterizer
│ ├── color.h
│ ├── color_bgr.h
│ ├── color_palette.c
│ ├── color_palette.h
│ ├── color_rgb.h
│ ├── error.c
│ ├── error.h
│ ├── ext_math.c
│ ├── ext_math.h
│ ├── framebuffer.c
│ ├── framebuffer.h
│ ├── global_state.c
│ ├── global_state.h
│ ├── helper.h
│ ├── image.c
│ ├── image.h
│ ├── indexbuffer.c
│ ├── indexbuffer.h
│ ├── matrix4.c
│ ├── matrix4.h
│ ├── pixel.h
│ ├── raster_triangle.h
│ ├── raster_vertex.h
│ ├── rect.c
│ ├── rect.h
│ ├── render.c
│ ├── render.h
│ ├── state_machine.c
│ ├── state_machine.h
│ ├── static_config.h
│ ├── texture.c
│ ├── texture.h
│ ├── vector2.h
│ ├── vector3.c
│ ├── vector3.h
│ ├── vector4.h
│ ├── vector_arithmetic.h
│ ├── vertex.c
│ ├── vertex.h
│ ├── vertexbuffer.c
│ ├── vertexbuffer.h
│ ├── viewport.c
│ └── viewport.h
└── test
├── README.txt
├── SDL2
└── main.c
├── linux
└── main.c
├── macos
└── main.m
├── media
├── banner.png
├── crate.png
├── front.png
├── grid.png
├── house.jpg
├── house_lines.pico
├── house_tris.pico
├── npot_tex_127.png
├── npot_tex_129.png
├── palette1.png
├── preview_macos.png
├── preview_win32.png
└── tiles.png
└── win32
└── main.c
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | # === CMake lists for the PicoRenderer - (07/09/2014) ===
3 |
4 | cmake_minimum_required(VERSION 2.8)
5 | project(PicoRenderer)
6 |
7 |
8 | # === Options ===
9 |
10 | option(PICO_USE_SDL2 "Use SDL2 as render context" OFF)
11 |
12 |
13 | # === Build path ===
14 |
15 | set(dir ${CMAKE_CURRENT_BINARY_DIR}/build)
16 | set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
17 | set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
18 |
19 |
20 | # === Preprocessor definitions ===
21 |
22 | add_definitions(-D_CRT_SECURE_NO_WARNINGS)
23 |
24 |
25 | # === Global files ===
26 |
27 | file(GLOB HeadersMain ${PROJECT_SOURCE_DIR}/inc/*.*)
28 | file(GLOB SourcesMain ${PROJECT_SOURCE_DIR}/src/*.*)
29 |
30 | file(GLOB SourcesRasterizer ${PROJECT_SOURCE_DIR}/src/rasterizer/*.*)
31 | file(GLOB SourcesPlatformBase ${PROJECT_SOURCE_DIR}/src/platform/*.*)
32 |
33 | if(PICO_USE_SDL2)
34 | file(GLOB SourcesPlatform ${PROJECT_SOURCE_DIR}/src/platform/SDL2/*.*)
35 | file(GLOB SourcesTest ${PROJECT_SOURCE_DIR}/test/SDL2/*.*)
36 | include_directories("${PROJECT_SOURCE_DIR}/src/platform/SDL2")
37 | elseif(WIN32)
38 | file(GLOB SourcesPlatform ${PROJECT_SOURCE_DIR}/src/platform/win32/*.*)
39 | file(GLOB SourcesTest ${PROJECT_SOURCE_DIR}/test/win32/*.*)
40 | include_directories("${PROJECT_SOURCE_DIR}/src/platform/win32")
41 | elseif(APPLE)
42 | file(GLOB SourcesPlatform ${PROJECT_SOURCE_DIR}/src/platform/macos/*.*)
43 | file(GLOB SourcesTest ${PROJECT_SOURCE_DIR}/test/macos/*.*)
44 | include_directories("${PROJECT_SOURCE_DIR}/src/platform/macos")
45 | elseif(UNIX)
46 | file(GLOB SourcesPlatform ${PROJECT_SOURCE_DIR}/src/platform/linux/*.*)
47 | file(GLOB SourcesTest ${PROJECT_SOURCE_DIR}/test/linux/*.*)
48 | include_directories("${PROJECT_SOURCE_DIR}/src/platform/linux")
49 | else()
50 | message(FATAL_ERROR "Unsupported platform")
51 | endif()
52 |
53 |
54 | # === Include directories ===
55 |
56 | include_directories("${PROJECT_SOURCE_DIR}/src/rasterizer")
57 | include_directories("${PROJECT_SOURCE_DIR}/src/")
58 | include_directories("${PROJECT_SOURCE_DIR}/inc/")
59 |
60 |
61 | # === Source groups ===
62 |
63 | source_group(
64 | "src\\rasterizer"
65 | FILES
66 | ${SourcesRasterizer}
67 | )
68 |
69 | source_group(
70 | "src\\platform"
71 | FILES
72 | ${SourcesPlatformBase}
73 | ${SourcesPlatform}
74 | )
75 |
76 | source_group(
77 | "inc"
78 | FILES
79 | ${HeadersMain}
80 | )
81 |
82 | source_group(
83 | "src"
84 | FILES
85 | ${SourcesMain}
86 | )
87 |
88 | source_group(
89 | "test1"
90 | FILES
91 | ${SourcesTest}
92 | )
93 |
94 |
95 | # === Executable ===
96 |
97 | add_library(
98 | pico_renderer
99 | ${SourcesMain}
100 | ${HeadersMain}
101 | ${SourcesRasterizer}
102 | ${SourcesPlatformBase}
103 | ${SourcesPlatform}
104 | ${PROJECT_SOURCE_DIR}/src/pico.c
105 | )
106 |
107 | if(APPLE)
108 | add_executable(
109 | test1
110 | MACOSX_BUNDLE
111 | ${SourcesTest}
112 | )
113 | else()
114 | add_executable(
115 | test1
116 | ${SourcesTest}
117 | )
118 | endif()
119 |
120 |
121 | if(PICO_USE_SDL2)
122 | target_link_libraries(test1 pico_renderer SDL2 m)
123 | elseif(WIN32)
124 | target_link_libraries(test1 pico_renderer)
125 | elseif(APPLE)
126 | find_library(COCOA_LIBRARY Cocoa)
127 | target_link_libraries(test1 ${COCOA_LIBRARY} pico_renderer)
128 | elseif(UNIX)
129 | target_link_libraries(pico_renderer X11 m)
130 | target_link_libraries(test1 pico_renderer X11)
131 | endif()
132 |
133 | set_target_properties(pico_renderer PROPERTIES LINKER_LANGUAGE C)
134 | set_target_properties(test1 PROPERTIES LINKER_LANGUAGE C)
135 |
--------------------------------------------------------------------------------
/FindPicoRenderer.cmake:
--------------------------------------------------------------------------------
1 |
2 | # Custom CMake module for finding "PicoRenderer" files
3 | # Written by Lukas Hermanns on 24/08/2015
4 |
5 | # Macros
6 |
7 | macro(_PR_APPEND_LIBRARIES _list _release)
8 | set(_debug ${_release}_DEBUG)
9 | if(${_debug})
10 | set(${_list} ${${_list}} optimized ${${_release}} debug ${${_debug}})
11 | else()
12 | set(${_list} ${${_list}} ${${_release}})
13 | endif()
14 | endmacro()
15 |
16 | # Find library
17 |
18 | find_path(PicoRenderer_INCLUDE_DIR pico.h)
19 |
20 | find_library(PicoRenderer_LIBRARY NAMES pico_renderer)
21 | find_library(PicoRenderer_LIBRARY_DEBUG NAMES pico_renderer)
22 |
23 | # Setup package handle
24 |
25 | include(FindPackageHandleStandardArgs)
26 |
27 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(
28 | PicoRenderer
29 | DEFAULT_MSG
30 | PicoRenderer_INCLUDE_DIR
31 | PicoRenderer_LIBRARY
32 | PicoRenderer_LIBRARY_DEBUG
33 | )
34 |
35 | if(PICORENDERER_FOUND)
36 | set(PicoRenderer_FOUND TRUE)
37 | _PR_APPEND_LIBRARIES(PicoRenderer_LIBRARIES PicoRenderer_LIBRARY)
38 | endif(PICORENDERER_FOUND)
39 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) 2014 Lukas Hermanns
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met:
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | 2. Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | 3. Neither the names of the copyright holders nor the names of any
13 | contributors may be used to endorse or promote products derived from this
14 | software without specific prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PicoRenderer
2 | ============
3 |
4 | This project provides a simple, 8-bit colored, 3D software renderer written in C99.
5 | It has an interface similiar to OpenGL 1.1.
6 |
7 |
8 | Overview
9 | --------
10 |
11 | - **Version**: 1.00 Alpha
12 | - **License**: [3-Clause BSD License](https://github.com/LukasBanana/PicoRenderer/blob/master/LICENSE.txt)
13 |
14 |
15 | Screenshots
16 | -----------
17 |
18 |

19 | Example scene (test1 on Windows 10)
20 |
21 |
22 | Supported Platforms
23 | -------------------
24 |
25 | - Windows (tested on Windows 10)
26 | - MacOS (tested on OSX El Capitan)
27 | - Linux (demo not available)
28 |
29 |
30 | Why C and not C++?
31 | ------------------
32 |
33 | C code is slim, highly portable, compiles fast and for a low-level software renderer one doesn't need lots of object-oriented or templated code.
34 |
35 |
36 | Build
37 | -----
38 |
39 | - CMake 2.8 (http://www.cmake.org/)
40 | - C99 compliant compiler
41 |
42 |
43 | Fine Tuning
44 | -----------
45 |
46 | There are several macros which allows you to enabled or disable specific features for fine tuning.
47 | For example if "PR_FAST_MATH" is defined, all uses of the sine function ('sinf' from the C standard library) will be replaced by "_aprx_sin" which implements an approximated and fast sine function (in src/rasterizer/ext_math.c).
48 | See src/rasterizer/static_config.h for all these macros.
49 |
50 |
51 | Plugins
52 | -------
53 |
54 | This project makes use of the "stb_image" library (see https://github.com/nothings/stb)
55 |
56 |
57 | Getting Started
58 | ---------------
59 |
60 | ```c
61 | // PicoRenderer (PR) interface example
62 | // (interface still in development)
63 | #include
64 |
65 | int main()
66 | {
67 | if (!prInit())
68 | return 1;
69 |
70 | // Create OS dependent window, this is your task ;-)
71 | PRuint scrWidth = 800, scrHeight = 600;
72 | PRcontextdesc contextDesc;
73 |
74 | /*
75 | #if defined(_WIN32)
76 |
77 | HWND wnd = CreateWindow(...);
78 | contextDesc.window = (void*)(&wnd);
79 |
80 | #elif defined(__APPLE__)
81 |
82 | NSWindow* wnd = [[NSWindow alloc] ...];
83 | contextDesc.window = (void*)wnd;
84 |
85 | #elif defined(__linux__)
86 |
87 | Window wnd = XCreateWindow(...);
88 | contextDesc.window = (void*)wnd;
89 |
90 | #endif
91 | */
92 |
93 | // Create render context
94 | PRobject context = prCreateContext(&contextDesc, scrWidth, scrHeight);
95 | //prMakeCurrent(context);
96 |
97 | // Create frame buffer
98 | PRobject frameBuffer = prCreateFrameBuffer(scrWidth, scrHeight);
99 | prBindFrameBuffer(frameBuffer);
100 |
101 | prViewport(0, 0, scrWidth, scrHeight);
102 |
103 | // Setup projection matrix
104 | PRfloat projection[16];
105 | prBuildPerspectiveProjection(
106 | projection, // output matrix
107 | (PRfloat)scrWidth/scrHeight, // aspect ratio
108 | 1.0f, // near clipping plane
109 | 100.0f, // far clipping plane
110 | 74.0f * PR_DEG2RAD // field of view (FOV) in radians (74 degrees to radians)
111 | );
112 | prProjectionMatrix(projection);
113 |
114 | // World transform
115 | PRfloat worldMatrix[16];
116 | PRfloat rotation = 0.0f;
117 |
118 | // Main loop
119 | PRboolean isQuit = PR_FALSE;
120 |
121 | while (!isQuit)
122 | {
123 | // Update user input ...
124 |
125 | // Setup world matrix
126 | prLoadIdentity(worldMatrix);
127 | prTranslate(worldMatrix, 0, 0, 2);
128 | prRotate(worldMatrix, 0, 0, 1, rotation);
129 | prWorldMatrix(worldMatrix);
130 | rotation += 0.01f;
131 |
132 | // Clear scene (with black background)
133 | prClearColor(0, 0, 0);
134 | prClearFrameBuffer(
135 | frameBuffer,
136 | 0.0f,
137 | PR_COLOR_BUFFER_BIT | PR_DEPTH_BUFFER_BIT
138 | );
139 |
140 | // Draw yellow triangle
141 | prColor(255, 255, 0);
142 | prBegin(PR_TRIANGLES);
143 | {
144 | prVertex2f(0, 1.155f);
145 | prVertex2f(1, -0.577f);
146 | prVertex2f(-1, -0.577f);
147 | }
148 | prEnd();
149 |
150 | // Show frame buffer on render context
151 | prPresent(context);
152 | }
153 |
154 | // Release all objects
155 | prDeleteFrameBuffer(frameBuffer);
156 | prDeleteContext(context);
157 |
158 | prRelease();
159 |
160 | return 0;
161 | }
162 | ```
163 |
--------------------------------------------------------------------------------
/inc/consts.h:
--------------------------------------------------------------------------------
1 | /*
2 | * consts.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_CONSTS_H
9 | #define PR_CONSTS_H
10 |
11 |
12 | #define PR_MATH_PI 3.14159265359f
13 |
14 | #define PR_RAD2DEG (180.0f / PR_MATH_PI)
15 | #define PR_DEG2RAD (PR_MATH_PI / 180.0f)
16 |
17 |
18 | #endif
19 |
--------------------------------------------------------------------------------
/inc/enums.h:
--------------------------------------------------------------------------------
1 | /*
2 | * enums.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_ENUMS_H
9 | #define PR_ENUMS_H
10 |
11 |
12 | // Color formats
13 | #define PR_UBYTE_RGB 0x00000001
14 | //#define PR_UBYTE_RGBA 0x00000002
15 |
16 | // prGetString arguments
17 | #define PR_STRING_VERSION 0x00000011
18 | #define PR_STRING_RENDERER 0x00000012
19 | #define PR_STRING_PLUGINS 0x00000013
20 |
21 | // prGetIntegerv arguments
22 | #define PR_MAX_TEXTURE_SIZE 0x00000021
23 |
24 | // Geometry primitives
25 | #define PR_POINTS 0x00000031
26 | #define PR_LINES 0x00000032
27 | #define PR_LINE_STRIP 0x00000033
28 | #define PR_LINE_LOOP 0x00000034
29 | #define PR_TRIANGLES 0x00000035
30 | #define PR_TRIANGLE_STRIP 0x00000036
31 | #define PR_TRIANGLE_FAN 0x00000037
32 |
33 | // Cull modes
34 | #define PR_CULL_NONE 0x00000040
35 | #define PR_CULL_FRONT 0x00000041
36 | #define PR_CULL_BACK 0x00000042
37 |
38 | // Polygon modes
39 | #define PR_POLYGON_FILL 0x00000053
40 | #define PR_POLYGON_LINE 0x00000054
41 | #define PR_POLYGON_POINT 0x00000055
42 |
43 | // prGetTexLevelParameteri arguments
44 | #define PR_TEXTURE_WIDTH 0x00000060
45 | #define PR_TEXTURE_HEIGHT 0x00000061
46 |
47 | // States
48 | #define PR_SCISSOR 0
49 | #define PR_MIP_MAPPING 1
50 |
51 | // Texture environment parameters
52 | #define PR_TEXTURE_LOD_BIAS 0
53 |
54 | // Frame buffer clear flags
55 | #define PR_COLOR_BUFFER_BIT 0x00000001
56 | #define PR_DEPTH_BUFFER_BIT 0x00000002
57 |
58 |
59 | #endif
60 |
--------------------------------------------------------------------------------
/inc/error_ids.h:
--------------------------------------------------------------------------------
1 | /*
2 | * error_ids.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_ERROR_IDS_H
9 | #define PR_ERROR_IDS_H
10 |
11 |
12 | typedef void (*PR_ERROR_HANDLER_PROC)(PRenum errorID, const char* info);
13 |
14 |
15 | //! No error
16 | #define PR_ERROR_NONE 0
17 |
18 | //! Null pointer error
19 | #define PR_ERROR_NULL_POINTER 1
20 |
21 | //! Invalid argument error
22 | #define PR_ERROR_INVALID_ARGUMENT 2
23 |
24 | //! Invalid ID error
25 | #define PR_ERROR_INVALID_ID 3
26 |
27 | //! Invalid state error
28 | #define PR_ERROR_INVALID_STATE 4
29 |
30 | //! Index out of bounds error
31 | #define PR_ERROR_INDEX_OUT_OF_BOUNDS 5
32 |
33 | //! Argument mismatch error
34 | #define PR_ERROR_ARGUMENT_MISMATCH 6
35 |
36 | //! Missing plugin error
37 | #define PR_ERROR_MISSING_PLUGIN 7
38 |
39 | //! Unexpected end-of-file error
40 | #define PR_ERROR_UNEXPECTED_EOF 8
41 |
42 | //! Context creation error (e.g. when X11 server is missing on a Linux system)
43 | #define PR_ERROR_CONTEXT 9
44 |
45 | //! Fatal error (occures only in debug mode)
46 | #define PR_ERROR_FATAL 10
47 |
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/inc/platform.h:
--------------------------------------------------------------------------------
1 | /*
2 | * platform.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_PLATFORM_H
9 | #define PR_PLATFORM_H
10 |
11 |
12 | //! Render context description structure.
13 | typedef struct PRcontextdesc
14 | {
15 | /**
16 | Reference to the OS dependent window.
17 | - For Win32, this must be from type 'const HWND*'
18 | - For MacOS, this must be from type 'const NSWindow*'
19 | - For Linux, this must be from type 'const Window*'
20 | */
21 | const void* window;
22 | }
23 | PRcontextdesc;
24 |
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/inc/structs.h:
--------------------------------------------------------------------------------
1 | /*
2 | * structs.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_STRUCTS_H
9 | #define PR_STRUCTS_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | //! Vertex structure. Coordinates: X, Y, Z; Texture-coordinates: U, V.
16 | typedef struct PRvertex
17 | {
18 | PRfloat x, y, z, u, v;
19 | }
20 | PRvertex;
21 |
22 |
23 | #endif
24 |
--------------------------------------------------------------------------------
/inc/types.h:
--------------------------------------------------------------------------------
1 | /*
2 | * types.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_TYPES_H
9 | #define PR_TYPES_H
10 |
11 |
12 | #include
13 |
14 |
15 | #define PR_TRUE 1
16 | #define PR_FALSE 0
17 |
18 | #ifdef _MSC_VER
19 | # define PR_INLINE _inline
20 | #else
21 | # define PR_INLINE static inline
22 | #endif
23 |
24 |
25 | //! Boolean type.
26 | typedef char PRboolean;
27 |
28 | //! 8-bit signed integer.
29 | typedef char PRbyte;
30 | //! 8-bit unsigned integer.
31 | typedef unsigned char PRubyte;
32 |
33 | //! 16-bit signed integer.
34 | typedef short PRshort;
35 | //! 16-bit unsigned integer.
36 | typedef unsigned short PRushort;
37 |
38 | //! 32-bit signed integer.
39 | typedef int PRint;
40 | //! 32-bit unsigned integer.
41 | typedef unsigned int PRuint;
42 |
43 | //! 32-bit floating-point.
44 | typedef float PRfloat;
45 | //! 64-bit floating-point.
46 | typedef double PRdouble;
47 |
48 | //! Enumeration type.
49 | typedef unsigned int PRenum;
50 | //! Bit field type used for flags.
51 | typedef unsigned int PRbitfield;
52 | //! Size type.
53 | typedef int PRsizei;
54 |
55 | //! Texture size type: 8-bit unsigned byte.
56 | typedef PRshort PRtexsize;
57 |
58 | //! No type or used for void pointer.
59 | typedef void PRvoid;
60 |
61 | //! Object type.
62 | typedef void* PRobject;
63 |
64 |
65 | #endif
66 |
--------------------------------------------------------------------------------
/src/pico.c:
--------------------------------------------------------------------------------
1 | /*
2 | * pico.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "pico.h"
9 | #include "error.h"
10 | #include "context.h"
11 | #include "framebuffer.h"
12 | #include "vertexbuffer.h"
13 | #include "indexbuffer.h"
14 | #include "texture.h"
15 | #include "image.h"
16 | #include "state_machine.h"
17 | #include "global_state.h"
18 | #include "render.h"
19 | #include "helper.h"
20 |
21 | #include
22 |
23 |
24 | // --- common --- //
25 |
26 | PRboolean prInit()
27 | {
28 | _pr_state_machine_init_null();
29 | _pr_global_state_init();
30 | return PR_TRUE;
31 | }
32 |
33 | PRboolean prRelease()
34 | {
35 | _pr_global_state_release();
36 | return PR_TRUE;
37 | }
38 |
39 | PRenum prGetError()
40 | {
41 | return _pr_error_get();
42 | }
43 |
44 | void prErrorHandler(PR_ERROR_HANDLER_PROC errorHandler)
45 | {
46 | _pr_error_set_handler(errorHandler);
47 | }
48 |
49 | const char* prGetString(PRenum str)
50 | {
51 | switch (str)
52 | {
53 | case PR_STRING_VERSION:
54 | return PR_VERSION_STR;
55 | case PR_STRING_RENDERER:
56 | return "Pico Renderer";
57 | case PR_STRING_PLUGINS:
58 | #ifdef PR_INCLUDE_PLUGINS
59 | return "stb_image;";
60 | #else
61 | return "";
62 | #endif
63 | }
64 | return NULL;
65 | }
66 |
67 | PRint prGetIntegerv(PRenum param)
68 | {
69 | switch (param)
70 | {
71 | case PR_MAX_TEXTURE_SIZE:
72 | return PR_MAX_TEX_SIZE;
73 | }
74 | return 0;
75 | }
76 |
77 | // --- context --- //
78 |
79 | PRobject prCreateContext(const PRcontextdesc* desc, PRuint width, PRuint height)
80 | {
81 | return (PRobject)_pr_context_create(desc, width, height);
82 | }
83 |
84 | void prDeleteContext(PRobject context)
85 | {
86 | _pr_context_delete((pr_context*)context);
87 | }
88 |
89 | void prMakeCurrent(PRobject context)
90 | {
91 | _pr_context_makecurrent((pr_context*)context);
92 | }
93 |
94 | void prPresent(PRobject context)
95 | {
96 | _pr_context_present((pr_context*)context, PR_STATE_MACHINE.boundFrameBuffer);
97 | }
98 |
99 | // --- framebuffer --- //
100 |
101 | PRobject prCreateFrameBuffer(PRuint width, PRuint height)
102 | {
103 | return (PRobject)_pr_framebuffer_create(width, height);
104 | }
105 |
106 | void prDeleteFrameBuffer(PRobject frameBuffer)
107 | {
108 | _pr_framebuffer_delete((pr_framebuffer*)frameBuffer);
109 | }
110 |
111 | void prBindFrameBuffer(PRobject frameBuffer)
112 | {
113 | _pr_state_machine_bind_framebuffer((pr_framebuffer*)frameBuffer);
114 | }
115 |
116 | void prClearFrameBuffer(PRobject frameBuffer, PRfloat clearDepth, PRbitfield clearFlags)
117 | {
118 | _pr_framebuffer_clear((pr_framebuffer*)frameBuffer, clearDepth, clearFlags);
119 | }
120 |
121 | // --- texture --- //
122 |
123 | PRobject prCreateTexture()
124 | {
125 | return (PRobject)_pr_texture_create();
126 | }
127 |
128 | void prDeleteTexture(PRobject texture)
129 | {
130 | _pr_texture_delete((pr_texture*)texture);
131 | }
132 |
133 | void prBindTexture(PRobject texture)
134 | {
135 | _pr_state_machine_bind_texture((pr_texture*)texture);
136 | }
137 |
138 | void prTexImage2D(
139 | PRobject texture, PRtexsize width, PRtexsize height, PRenum format,
140 | const PRvoid* data, PRboolean dither, PRboolean generateMips)
141 | {
142 | _pr_texture_image2d((pr_texture*)texture, width, height, format, data, dither, generateMips);
143 | }
144 |
145 | void prTexImage2DFromFile(
146 | PRobject texture, const char* filename, PRboolean dither, PRboolean generateMips)
147 | {
148 | pr_image* image = _pr_image_load_from_file(filename);
149 |
150 | _pr_texture_image2d(
151 | (pr_texture*)texture,
152 | (PRtexsize)(image->width),
153 | (PRtexsize)(image->height),
154 | PR_UBYTE_RGB,
155 | image->colors,
156 | dither,
157 | generateMips
158 | );
159 |
160 | _pr_image_delete(image);
161 | }
162 |
163 | void prTexEnvi(PRenum param, PRint value)
164 | {
165 | _pr_state_machine_set_texenvi(param, value);
166 | }
167 |
168 | PRint prGetTexLevelParameteri(PRobject texture, PRubyte mipLevel, PRenum param)
169 | {
170 | return _pr_texture_get_mip_parameter((const pr_texture*)texture, mipLevel, param);
171 | }
172 |
173 | // --- vertexbuffer --- //
174 |
175 | PRobject prCreateVertexBuffer()
176 | {
177 | return (PRobject)_pr_vertexbuffer_create();
178 | }
179 |
180 | void prDeleteVertexBuffer(PRobject vertexBuffer)
181 | {
182 | _pr_vertexbuffer_delete((pr_vertexbuffer*)vertexBuffer);
183 | }
184 |
185 | void prVertexBufferData(PRobject vertexBuffer, PRsizei numVertices, const PRvoid* coords, const PRvoid* texCoords, PRsizei vertexStride)
186 | {
187 | _pr_vertexbuffer_data((pr_vertexbuffer*)vertexBuffer, numVertices, coords, texCoords, vertexStride);
188 | }
189 |
190 | void prVertexBufferDataFromFile(PRobject vertexBuffer, PRsizei* numVertices, FILE* file)
191 | {
192 | _pr_vertexbuffer_data_from_file((pr_vertexbuffer*)vertexBuffer, numVertices, file);
193 | }
194 |
195 | void prBindVertexBuffer(PRobject vertexBuffer)
196 | {
197 | _pr_state_machine_bind_vertexbuffer((pr_vertexbuffer*)vertexBuffer);
198 | }
199 |
200 | // --- indexbuffer --- //
201 |
202 | PRobject prCreateIndexBuffer()
203 | {
204 | return (PRobject)_pr_indexbuffer_create();
205 | }
206 |
207 | void prDeleteIndexBuffer(PRobject indexBuffer)
208 | {
209 | _pr_indexbuffer_delete((pr_indexbuffer*)indexBuffer);
210 | }
211 |
212 | void prIndexBufferData(PRobject indexBuffer, const PRushort* indices, PRsizei numIndices)
213 | {
214 | _pr_indexbuffer_data((pr_indexbuffer*)indexBuffer, indices, numIndices);
215 | }
216 |
217 | void prIndexBufferDataFromFile(PRobject indexBuffer, PRsizei* numIndices, FILE* file)
218 | {
219 | _pr_indexbuffer_data_from_file((pr_indexbuffer*)indexBuffer, numIndices, file);
220 | }
221 |
222 | void prBindIndexBuffer(PRobject indexBuffer)
223 | {
224 | _pr_state_machine_bind_indexbuffer((pr_indexbuffer*)indexBuffer);
225 | }
226 |
227 | // --- matrices --- //
228 |
229 | void prProjectionMatrix(const PRfloat* matrix4x4)
230 | {
231 | _pr_state_machine_projection_matrix((pr_matrix4*)matrix4x4);
232 | }
233 |
234 | void prViewMatrix(const PRfloat* matrix4x4)
235 | {
236 | _pr_state_machine_view_matrix((pr_matrix4*)matrix4x4);
237 | }
238 |
239 | void prWorldMatrix(const PRfloat* matrix4x4)
240 | {
241 | _pr_state_machine_world_matrix((pr_matrix4*)matrix4x4);
242 | }
243 |
244 | void prBuildPerspectiveProjection(
245 | PRfloat* matrix4x4, PRfloat aspectRatio, PRfloat nearPlane, PRfloat farPlane, PRfloat fov)
246 | {
247 | _pr_matrix_build_perspective((pr_matrix4*)matrix4x4, aspectRatio, nearPlane, farPlane, fov);
248 | }
249 |
250 | void prBuildOrthogonalProjection(
251 | PRfloat* matrix4x4, PRfloat width, PRfloat height, PRfloat nearPlane, PRfloat farPlane)
252 | {
253 | _pr_matrix_build_orthogonal((pr_matrix4*)matrix4x4, width, height, nearPlane, farPlane);
254 | }
255 |
256 | void prTranslate(PRfloat* matrix4x4, PRfloat x, PRfloat y, PRfloat z)
257 | {
258 | _pr_matrix_translate((pr_matrix4*)matrix4x4, x, y, z);
259 | }
260 |
261 | void prRotate(PRfloat* matrix4x4, PRfloat x, PRfloat y, PRfloat z, PRfloat angle)
262 | {
263 | _pr_matrix_rotate((pr_matrix4*)matrix4x4, x, y, z, angle);
264 | }
265 |
266 | void prScale(PRfloat* matrix4x4, PRfloat x, PRfloat y, PRfloat z)
267 | {
268 | _pr_matrix_scale((pr_matrix4*)matrix4x4, x, y, z);
269 | }
270 |
271 | void prLoadIdentity(PRfloat* matrix4x4)
272 | {
273 | _pr_matrix_load_identity((pr_matrix4*)matrix4x4);
274 | }
275 |
276 | // --- states --- //
277 |
278 | void prSetState(PRenum cap, PRboolean state)
279 | {
280 | _pr_state_machine_set_state(cap, state);
281 | }
282 |
283 | PRboolean prGetState(PRenum cap)
284 | {
285 | return _pr_state_machine_get_state(cap);
286 | }
287 |
288 | void prEnable(PRenum cap)
289 | {
290 | _pr_state_machine_set_state(cap, PR_TRUE);
291 | }
292 |
293 | void prDisable(PRenum cap)
294 | {
295 | _pr_state_machine_set_state(cap, PR_FALSE);
296 | }
297 |
298 | void prViewport(PRint x, PRint y, PRint width, PRint height)
299 | {
300 | _pr_state_machine_viewport(x, y, width, height);
301 | }
302 |
303 | void prScissor(PRint x, PRint y, PRint width, PRint height)
304 | {
305 | _pr_state_machine_scissor(x, y, width, height);
306 | }
307 |
308 | void prDepthRange(PRfloat minDepth, PRfloat maxDepth)
309 | {
310 | _pr_state_machine_depth_range(minDepth, maxDepth);
311 | }
312 |
313 | void prCullMode(PRenum mode)
314 | {
315 | _pr_state_machine_cull_mode(mode);
316 | }
317 |
318 | void prPolygonMode(PRenum mode)
319 | {
320 | _pr_state_machine_polygon_mode(mode);
321 | }
322 |
323 | // --- drawing --- //
324 |
325 | void prClearColor(PRubyte r, PRubyte g, PRubyte b)
326 | {
327 | PR_STATE_MACHINE.clearColor = _pr_color_to_colorindex(r, g, b);
328 | }
329 |
330 | void prColor(PRubyte r, PRubyte g, PRubyte b)
331 | {
332 | PR_STATE_MACHINE.color0 = _pr_color_to_colorindex(r, g, b);
333 | }
334 |
335 | void prDrawScreenPoint(PRint x, PRint y)
336 | {
337 | _pr_render_screenspace_point(x, y);
338 | }
339 |
340 | void prDrawScreenLine(PRint x1, PRint y1, PRint x2, PRint y2)
341 | {
342 | _pr_render_screenspace_line(x1, y1, x2, y2);
343 | }
344 |
345 | void prDrawScreenImage(PRint left, PRint top, PRint right, PRint bottom)
346 | {
347 | _pr_render_screenspace_image(left, top, right, bottom);
348 | }
349 |
350 | void prDraw(PRenum primitives, PRushort numVertices, PRushort firstVertex)
351 | {
352 | switch (primitives)
353 | {
354 | case PR_POINTS:
355 | _pr_render_points(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer);
356 | break;
357 |
358 | case PR_LINES:
359 | _pr_render_lines(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer);
360 | break;
361 | case PR_LINE_STRIP:
362 | _pr_render_line_strip(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer);
363 | break;
364 | case PR_LINE_LOOP:
365 | _pr_render_line_loop(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer);
366 | break;
367 |
368 | case PR_TRIANGLES:
369 | _pr_render_triangles(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer);
370 | break;
371 | case PR_TRIANGLE_STRIP:
372 | _pr_render_triangle_strip(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer);
373 | break;
374 | case PR_TRIANGLE_FAN:
375 | _pr_render_triangle_fan(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer);
376 | break;
377 |
378 | default:
379 | PR_ERROR(PR_ERROR_INVALID_ARGUMENT);
380 | break;
381 | }
382 | }
383 |
384 | void prDrawIndexed(PRenum primitives, PRushort numVertices, PRushort firstVertex)
385 | {
386 | switch (primitives)
387 | {
388 | case PR_POINTS:
389 | _pr_render_indexed_points(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer, PR_STATE_MACHINE.boundIndexBuffer);
390 | break;
391 |
392 | case PR_LINES:
393 | _pr_render_indexed_lines(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer, PR_STATE_MACHINE.boundIndexBuffer);
394 | break;
395 | case PR_LINE_STRIP:
396 | _pr_render_indexed_line_strip(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer, PR_STATE_MACHINE.boundIndexBuffer);
397 | break;
398 | case PR_LINE_LOOP:
399 | _pr_render_indexed_line_loop(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer, PR_STATE_MACHINE.boundIndexBuffer);
400 | break;
401 |
402 | case PR_TRIANGLES:
403 | _pr_render_indexed_triangles(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer, PR_STATE_MACHINE.boundIndexBuffer);
404 | break;
405 | case PR_TRIANGLE_STRIP:
406 | _pr_render_indexed_triangle_strip(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer, PR_STATE_MACHINE.boundIndexBuffer);
407 | break;
408 | case PR_TRIANGLE_FAN:
409 | _pr_render_indexed_triangle_fan(numVertices, firstVertex, PR_STATE_MACHINE.boundVertexBuffer, PR_STATE_MACHINE.boundIndexBuffer);
410 | break;
411 |
412 | default:
413 | PR_ERROR(PR_ERROR_INVALID_ARGUMENT);
414 | break;
415 | }
416 | }
417 |
418 | // --- immediate mode --- //
419 |
420 | void prBegin(PRenum primitives)
421 | {
422 | _pr_immediate_mode_begin(primitives);
423 | }
424 |
425 | void prEnd()
426 | {
427 | _pr_immediate_mode_end();
428 | }
429 |
430 | void prTexCoord2f(PRfloat u, PRfloat v)
431 | {
432 | _pr_immediate_mode_texcoord(u, v);
433 | }
434 |
435 | void prTexCoord2i(PRint u, PRint v)
436 | {
437 | _pr_immediate_mode_texcoord((PRfloat)u, (PRfloat)v);
438 | }
439 |
440 | void prVertex4f(PRfloat x, PRfloat y, PRfloat z, PRfloat w)
441 | {
442 | _pr_immediate_mode_vertex(x, y, z, w);
443 | }
444 |
445 | void prVertex4i(PRint x, PRint y, PRint z, PRint w)
446 | {
447 | _pr_immediate_mode_vertex((PRfloat)x, (PRfloat)y, (PRfloat)z, (PRfloat)w);
448 | }
449 |
450 | void prVertex3f(PRfloat x, PRfloat y, PRfloat z)
451 | {
452 | _pr_immediate_mode_vertex(x, y, z, 1.0f);
453 | }
454 |
455 | void prVertex3i(PRint x, PRint y, PRint z)
456 | {
457 | _pr_immediate_mode_vertex((PRfloat)x, (PRfloat)y, (PRfloat)z, 1.0f);
458 | }
459 |
460 | void prVertex2f(PRfloat x, PRfloat y)
461 | {
462 | _pr_immediate_mode_vertex(x, y, 0.0f, 1.0f);
463 | }
464 |
465 | void prVertex2i(PRint x, PRint y)
466 | {
467 | _pr_immediate_mode_vertex((PRfloat)x, (PRfloat)y, 0.0f, 1.0f);
468 | }
469 |
470 |
--------------------------------------------------------------------------------
/src/platform/SDL2/context.c:
--------------------------------------------------------------------------------
1 | /*
2 | * context.c (SDL2)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "context.h"
9 | #include "error.h"
10 | #include "helper.h"
11 |
12 | #include
13 |
14 |
15 | pr_context* _currentContext = NULL;
16 |
17 | pr_context* _pr_context_create(const PRcontextdesc* desc, PRuint width, PRuint height)
18 | {
19 | if (desc == NULL || desc->window == NULL || width <= 0 || height <= 0)
20 | {
21 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
22 | return NULL;
23 | }
24 |
25 | // Create render context
26 | pr_context* context = PR_MALLOC(pr_context);
27 |
28 | // Open SDL2 window
29 |
30 | if (desc->window == NULL)
31 | {
32 | _pr_error_set(PR_ERROR_CONTEXT, __FUNCTION__);
33 | return NULL;
34 | }
35 |
36 | // Create SDL2 objects
37 | context->wnd = (SDL_Window*)desc->window;
38 | context->ren = SDL_CreateRenderer(context->wnd, -1, SDL_RENDERER_SOFTWARE);
39 | context->tex = SDL_CreateTexture(context->ren, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, width, height);
40 | context->colors = PR_CALLOC(pr_color, width*height);
41 | context->width = width;
42 | context->height = height;
43 |
44 | if (context->ren == NULL)
45 | {
46 | _pr_error_set(PR_ERROR_CONTEXT, __FUNCTION__);
47 | return NULL;
48 | }
49 |
50 | if (context->tex == NULL)
51 | {
52 | _pr_error_set(PR_ERROR_CONTEXT, __FUNCTION__);
53 | return NULL;
54 | }
55 |
56 | // Create color palette
57 | context->colorPalette = PR_MALLOC(pr_color_palette);
58 | _pr_color_palette_fill_r3g3b2(context->colorPalette);
59 |
60 | // Initialize state machine
61 | _pr_state_machine_init(&(context->stateMachine));
62 | _pr_context_makecurrent(context);
63 |
64 | return context;
65 | }
66 |
67 | void _pr_context_delete(pr_context* context)
68 | {
69 | if (context != NULL)
70 | {
71 | _pr_ref_assert(&(context->stateMachine));
72 |
73 | // Free SDL2 objects
74 | SDL_DestroyTexture(context->tex);
75 | SDL_DestroyRenderer(context->ren);
76 | SDL_DestroyWindow(context->wnd);
77 |
78 | free(context->colorPalette);
79 | free(context->colors);
80 | free(context);
81 | }
82 | }
83 |
84 | void _pr_context_makecurrent(pr_context* context)
85 | {
86 | _currentContext = context;
87 | if (context != NULL)
88 | _pr_state_machine_makecurrent(&(context->stateMachine));
89 | else
90 | _pr_state_machine_makecurrent(NULL);
91 | }
92 |
93 | void _pr_context_present(pr_context* context, const pr_framebuffer* framebuffer)
94 | {
95 | if (context == NULL || framebuffer == NULL)
96 | {
97 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
98 | return;
99 | }
100 | /*if (context->width != framebuffer->width || context->height != framebuffer->height)
101 | {
102 | _pr_error_set(PR_ERROR_ARGUMENT_MISMATCH, __FUNCTION__);
103 | return;
104 | }*/
105 |
106 | // Get iterators
107 | const PRuint num = context->width*context->height;
108 |
109 | pr_color* dst = context->colors;
110 | pr_color* dstEnd = dst + num;
111 |
112 | const pr_pixel* pixels = framebuffer->pixels;
113 | const pr_color* palette = context->colorPalette->colors;
114 |
115 | #ifndef PR_COLOR_BUFFER_24BIT
116 | const pr_color* paletteColor;
117 | #endif
118 |
119 | // Iterate over all pixels
120 |
121 | while (dst != dstEnd)
122 | {
123 | #ifdef PR_COLOR_BUFFER_24BIT
124 | *dst = pixels->colorIndex;
125 | #else
126 | paletteColor = (palette + pixels->colorIndex);
127 |
128 | dst->r = paletteColor->r;
129 | dst->g = paletteColor->g;
130 | dst->b = paletteColor->b;
131 | #endif
132 |
133 | ++dst;
134 | ++pixels;
135 | }
136 | SDL_RenderClear(context->ren);
137 | SDL_UpdateTexture(context->tex, NULL, context->colors, context->width * (sizeof(Uint8) * 3));
138 | SDL_RenderCopy(context->ren, context->tex, NULL, NULL);
139 | SDL_RenderPresent(context->ren);
140 | }
141 |
--------------------------------------------------------------------------------
/src/platform/SDL2/context.h:
--------------------------------------------------------------------------------
1 | /*
2 | * context.h (SDL2)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_CONTEXT_H
9 | #define PR_CONTEXT_H
10 |
11 |
12 | #include "types.h"
13 | #include "framebuffer.h"
14 | #include "color_palette.h"
15 | #include "color.h"
16 | #include "platform.h"
17 | #include "state_machine.h"
18 |
19 | #include
20 |
21 |
22 | //! Render context structure.
23 | typedef struct pr_context
24 | {
25 | // SDL2 objects
26 | SDL_Window* wnd;
27 | SDL_Renderer* ren;
28 | SDL_Texture* tex;
29 |
30 | // Renderer objects
31 | pr_color* colors;
32 | PRuint width;
33 | PRuint height;
34 | pr_color_palette* colorPalette;
35 |
36 | // State objects
37 | pr_state_machine stateMachine;
38 | }
39 | pr_context;
40 |
41 |
42 | extern pr_context* _currentContext;
43 |
44 | //! Creates a new render context for the specified device context.
45 | pr_context* _pr_context_create(const PRcontextdesc* desc, PRuint width, PRuint height);
46 | //! Deletes the specified render context.
47 | void _pr_context_delete(pr_context* context);
48 |
49 | //! Makes the specified context to the current one.
50 | void _pr_context_makecurrent(pr_context* context);
51 |
52 | /**
53 | Presents the specified framebuffer onto the render context.
54 | Errors:
55 | - PR_ERROR_NULL_POINTER : If 'context', 'framebuffer' or 'colorPalette' is null.
56 | - PR_ERROR_ARGUMENT_MISMATCH : If 'context' has another dimension than 'framebuffer'.
57 | */
58 | void _pr_context_present(pr_context* context, const pr_framebuffer* framebuffer);
59 |
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/src/platform/linux/context.c:
--------------------------------------------------------------------------------
1 | /*
2 | * context.c (Linux)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "context.h"
9 | #include "error.h"
10 | #include "helper.h"
11 |
12 | #include
13 |
14 |
15 | pr_context* _currentContext = NULL;
16 |
17 | pr_context* _pr_context_create(const PRcontextdesc* desc, PRuint width, PRuint height)
18 | {
19 | if (desc == NULL || desc->window == NULL || width <= 0 || height <= 0)
20 | {
21 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
22 | return NULL;
23 | }
24 |
25 | // Create render context
26 | pr_context* context = PR_MALLOC(pr_context);
27 |
28 | // Open X11 display
29 | Display* display = XOpenDisplay(NULL);
30 |
31 | if (display == NULL)
32 | {
33 | _pr_error_set(PR_ERROR_CONTEXT, __FUNCTION__);
34 | return NULL;
35 | }
36 |
37 | // Create X11 objects
38 | context->wnd = *((Window*)desc->window);
39 | context->pmp = XCreatePixmap(display, context->wnd, width, height, 8);
40 | //todo...
41 |
42 | if (context->pmp == 0)
43 | {
44 | _pr_error_set(PR_ERROR_CONTEXT, __FUNCTION__);
45 | return NULL;
46 | }
47 |
48 | // Create color palette
49 | context->colorPalette = PR_MALLOC(pr_color_palette);
50 | _pr_color_palette_fill_r3g3b2(context->colorPalette);
51 |
52 | // Initialize state machine
53 | _pr_state_machine_init(&(context->stateMachine));
54 | _pr_context_makecurrent(context);
55 |
56 | return context;
57 | }
58 |
59 | void _pr_context_delete(pr_context* context)
60 | {
61 | if (context != NULL)
62 | {
63 | _pr_ref_assert(&(context->stateMachine));
64 |
65 | // Free X11 objects
66 | XFree(context->pmp);
67 |
68 | free(context->colorPalette);
69 | free(context->colors);
70 | free(context);
71 | }
72 | }
73 |
74 | void _pr_context_makecurrent(pr_context* context)
75 | {
76 | _currentContext = context;
77 | if (context != NULL)
78 | _pr_state_machine_makecurrent(&(context->stateMachine));
79 | else
80 | _pr_state_machine_makecurrent(NULL);
81 | }
82 |
83 | void _pr_context_present(pr_context* context, const pr_framebuffer* framebuffer)
84 | {
85 | if (context == NULL || framebuffer == NULL)
86 | {
87 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
88 | return;
89 | }
90 | if (context->width != framebuffer->width || context->height != framebuffer->height)
91 | {
92 | _pr_error_set(PR_ERROR_ARGUMENT_MISMATCH, __FUNCTION__);
93 | return;
94 | }
95 |
96 | // Get iterators
97 | const PRuint num = context->width*context->height;
98 |
99 | pr_color* dst = context->colors;
100 | pr_color* dstEnd = dst + num;
101 |
102 | const pr_pixel* pixels = framebuffer->pixels;
103 | const pr_color* palette = context->colorPalette->colors;
104 |
105 | #ifndef PR_COLOR_BUFFER_24BIT
106 | const pr_color* paletteColor;
107 | #endif
108 |
109 | // Iterate over all pixels
110 | while (dst != dstEnd)
111 | {
112 | #ifdef PR_COLOR_BUFFER_24BIT
113 | *dst = pixels->colorIndex;
114 | #else
115 | paletteColor = (palette + pixels->colorIndex);
116 |
117 | dst->r = paletteColor->r;
118 | dst->g = paletteColor->g;
119 | dst->b = paletteColor->b;
120 | #endif
121 |
122 | ++dst;
123 | ++pixels;
124 | }
125 |
126 | //todo...
127 | }
128 |
129 |
--------------------------------------------------------------------------------
/src/platform/linux/context.h:
--------------------------------------------------------------------------------
1 | /*
2 | * context.h (Linux)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_CONTEXT_H
9 | #define PR_CONTEXT_H
10 |
11 |
12 | #include "types.h"
13 | #include "framebuffer.h"
14 | #include "color_palette.h"
15 | #include "color.h"
16 | #include "platform.h"
17 | #include "state_machine.h"
18 |
19 | #include
20 |
21 |
22 | //! Render context structure.
23 | typedef struct pr_context
24 | {
25 | // X11 objects
26 | Window wnd;
27 | //GC gfx;
28 | Pixmap pmp;
29 |
30 | // Renderer objects
31 | pr_color* colors;
32 | PRuint width;
33 | PRuint height;
34 | pr_color_palette* colorPalette;
35 |
36 | // State objects
37 | pr_state_machine stateMachine;
38 | }
39 | pr_context;
40 |
41 |
42 | extern pr_context* _currentContext;
43 |
44 | //! Creates a new render context for the specified device context.
45 | pr_context* _pr_context_create(const PRcontextdesc* desc, PRuint width, PRuint height);
46 | //! Deletes the specified render context.
47 | void _pr_context_delete(pr_context* context);
48 |
49 | //! Makes the specified context to the current one.
50 | void _pr_context_makecurrent(pr_context* context);
51 |
52 | /**
53 | Presents the specified framebuffer onto the render context.
54 | Errors:
55 | - PR_ERROR_NULL_POINTER : If 'context', 'framebuffer' or 'colorPalette' is null.
56 | - PR_ERROR_ARGUMENT_MISMATCH : If 'context' has another dimension than 'framebuffer'.
57 | */
58 | void _pr_context_present(pr_context* context, const pr_framebuffer* framebuffer);
59 |
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/src/platform/macos/context.h:
--------------------------------------------------------------------------------
1 | /*
2 | * context.h (OSX)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_CONTEXT_H
9 | #define PR_CONTEXT_H
10 |
11 |
12 | #include "types.h"
13 | #include "framebuffer.h"
14 | #include "color_palette.h"
15 | #include "color.h"
16 | #include "platform.h"
17 | #include "state_machine.h"
18 |
19 |
20 | //! Render context structure.
21 | typedef struct pr_context
22 | {
23 | // OSX objects
24 | void* wnd;
25 | void* bmp;
26 |
27 | // Renderer objects
28 | PRuint width;
29 | PRuint height;
30 | pr_color_palette* colorPalette;
31 |
32 | // State objects
33 | pr_state_machine stateMachine;
34 | }
35 | pr_context;
36 |
37 |
38 | extern pr_context* _currentContext;
39 |
40 | //! Creates a new render context for the specified device context.
41 | pr_context* _pr_context_create(const PRcontextdesc* desc, PRuint width, PRuint height);
42 | //! Deletes the specified render context.
43 | void _pr_context_delete(pr_context* context);
44 |
45 | //! Makes the specified context to the current one.
46 | void _pr_context_makecurrent(pr_context* context);
47 |
48 | /**
49 | Presents the specified framebuffer onto the render context.
50 | Errors:
51 | - PR_ERROR_NULL_POINTER : If 'context', 'framebuffer' or 'colorPalette' is null.
52 | - PR_ERROR_ARGUMENT_MISMATCH : If 'context' has another dimension than 'framebuffer'.
53 | */
54 | void _pr_context_present(pr_context* context, const pr_framebuffer* framebuffer);
55 |
56 |
57 | #endif
58 |
--------------------------------------------------------------------------------
/src/platform/macos/context.m:
--------------------------------------------------------------------------------
1 | /*
2 | * context.c (OSX)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #import
9 |
10 | #include "context.h"
11 | #include "error.h"
12 | #include "helper.h"
13 |
14 |
15 | // Custom view to display context bitmap in NSWindow
16 |
17 | @interface PicoNSView : NSView
18 | {
19 | pr_context* context;
20 | }
21 |
22 | @end
23 |
24 | @implementation PicoNSView
25 |
26 | - (id)initWithFrame:(NSRect)frame ctx:(pr_context*)pContext;
27 | {
28 | self = [super initWithFrame:frame];
29 | context = pContext;
30 | return self;
31 | }
32 |
33 | - (void)drawRect:(NSRect)pRect
34 | {
35 | NSBitmapImageRep* bmp = (NSBitmapImageRep*)context->bmp;
36 | [bmp draw];
37 | }
38 |
39 | @end
40 |
41 |
42 | // MacOS specific graphics context
43 |
44 | pr_context* _currentContext = NULL;
45 |
46 | pr_context* _pr_context_create(const PRcontextdesc* desc, PRuint width, PRuint height)
47 | {
48 | if (desc == NULL || desc->window == NULL || width <= 0 || height <= 0)
49 | {
50 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
51 | return NULL;
52 | }
53 |
54 | // Create render context
55 | pr_context* context = PR_MALLOC(pr_context);
56 |
57 | // Store OSX objects
58 | context->wnd = (void*)desc->window;
59 | context->bmp = (void*)[[NSBitmapImageRep alloc]
60 | initWithBitmapDataPlanes: nil
61 | pixelsWide: width
62 | pixelsHigh: height
63 | bitsPerSample: 8
64 | samplesPerPixel: 3
65 | hasAlpha: NO
66 | isPlanar: NO
67 | colorSpaceName: NSDeviceRGBColorSpace//NSCalibratedRGBColorSpace
68 | bytesPerRow: (3 * width)
69 | bitsPerPixel: 24
70 | ];
71 |
72 | // Create graphics context
73 | NSWindow* wnd = (NSWindow*)desc->window;
74 |
75 | // Create pixel buffer
76 | context->width = width;
77 | context->height = height;
78 |
79 | // Create color palette
80 | context->colorPalette = PR_MALLOC(pr_color_palette);
81 | _pr_color_palette_fill_r3g3b2(context->colorPalette);
82 |
83 | // Initialize state machine
84 | _pr_state_machine_init(&(context->stateMachine));
85 | _pr_context_makecurrent(context);
86 |
87 | // Use custom view to display context bitmap
88 | wnd.contentView = [[PicoNSView alloc]
89 | initWithFrame: [[wnd contentView] bounds]
90 | ctx: context
91 | ];
92 |
93 | return context;
94 | }
95 |
96 | void _pr_context_delete(pr_context* context)
97 | {
98 | if (context != NULL)
99 | {
100 | _pr_ref_assert(&(context->stateMachine));
101 |
102 | // Delete OSX objects
103 | [((NSBitmapImageRep*)context->bmp) release];
104 |
105 | free(context->colorPalette);
106 | free(context);
107 | }
108 | }
109 |
110 | void _pr_context_makecurrent(pr_context* context)
111 | {
112 | _currentContext = context;
113 | if (context != NULL)
114 | _pr_state_machine_makecurrent(&(context->stateMachine));
115 | else
116 | _pr_state_machine_makecurrent(NULL);
117 | }
118 |
119 | void _pr_context_present(pr_context* context, const pr_framebuffer* framebuffer)
120 | {
121 | if (context == NULL || framebuffer == NULL)
122 | {
123 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
124 | return;
125 | }
126 | if (context->width != framebuffer->width || context->height != framebuffer->height)
127 | {
128 | _pr_error_set(PR_ERROR_ARGUMENT_MISMATCH, __FUNCTION__);
129 | return;
130 | }
131 |
132 | // Get iterators
133 | const PRuint num = context->width * context->height;
134 |
135 | NSBitmapImageRep* bmp = (NSBitmapImageRep*)context->bmp;
136 |
137 | pr_color* dst = (pr_color*)[bmp bitmapData];
138 | pr_color* dstEnd = dst + num;
139 |
140 | const pr_pixel* pixels = framebuffer->pixels;
141 |
142 | const pr_color* palette = context->colorPalette->colors;
143 | const pr_color* paletteColor;
144 |
145 | // Iterate over all pixels
146 | while (dst != dstEnd)
147 | {
148 | paletteColor = (palette + pixels->colorIndex);
149 |
150 | dst->r = paletteColor->r;
151 | dst->g = paletteColor->g;
152 | dst->b = paletteColor->b;
153 |
154 | ++dst;
155 | ++pixels;
156 | }
157 |
158 | // Trigger content view to be redrawn
159 | NSWindow* wnd = (NSWindow*)context->wnd;
160 | [[wnd contentView] setNeedsDisplay:YES];
161 | }
162 |
163 |
--------------------------------------------------------------------------------
/src/platform/win32/context.c:
--------------------------------------------------------------------------------
1 | /*
2 | * context.c (Win32)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "context.h"
9 | #include "error.h"
10 | #include "helper.h"
11 |
12 |
13 | pr_context* _currentContext = NULL;
14 |
15 | pr_context* _pr_context_create(const PRcontextdesc* desc, PRuint width, PRuint height)
16 | {
17 | if (desc == NULL || desc->window == NULL || width <= 0 || height <= 0)
18 | {
19 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
20 | return NULL;
21 | }
22 |
23 | // Create render context
24 | pr_context* context = PR_MALLOC(pr_context);
25 |
26 | // Setup bitmap info structure
27 | BITMAPINFO* bmi = (&context->bmpInfo);
28 | memset(bmi, 0, sizeof(BITMAPINFO));
29 |
30 | bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
31 | bmi->bmiHeader.biWidth = (LONG)width;
32 | bmi->bmiHeader.biHeight = (LONG)height;
33 | bmi->bmiHeader.biPlanes = 1;
34 | bmi->bmiHeader.biBitCount = 24;
35 | bmi->bmiHeader.biCompression = BI_RGB;
36 |
37 | // Setup context
38 | context->wnd = *((HWND*)desc->window);
39 | context->dc = GetDC(context->wnd);
40 | context->dcBmp = CreateCompatibleDC(context->dc);
41 | context->bmp = CreateCompatibleBitmap(context->dc, width, height);
42 | context->colors = PR_CALLOC(pr_color, width*height);
43 | context->width = width;
44 | context->height = height;
45 |
46 | SelectObject(context->dcBmp, context->bmp);
47 |
48 | // Create color palette
49 | context->colorPalette = PR_MALLOC(pr_color_palette);
50 | _pr_color_palette_fill_r3g3b2(context->colorPalette);
51 |
52 | // Initialize state machine
53 | _pr_state_machine_init(&(context->stateMachine));
54 | _pr_context_makecurrent(context);
55 |
56 | return context;
57 | }
58 |
59 | void _pr_context_delete(pr_context* context)
60 | {
61 | if (context != NULL)
62 | {
63 | _pr_ref_assert(&(context->stateMachine));
64 |
65 | if (context->bmp != NULL)
66 | DeleteObject(context->bmp);
67 | if (context->dcBmp != NULL)
68 | DeleteDC(context->dcBmp);
69 |
70 | free(context->colorPalette);
71 | free(context->colors);
72 | free(context);
73 | }
74 | }
75 |
76 | void _pr_context_makecurrent(pr_context* context)
77 | {
78 | _currentContext = context;
79 | if (context != NULL)
80 | _pr_state_machine_makecurrent(&(context->stateMachine));
81 | else
82 | _pr_state_machine_makecurrent(NULL);
83 | }
84 |
85 | void _pr_context_present(pr_context* context, const pr_framebuffer* framebuffer)
86 | {
87 | if (context == NULL || framebuffer == NULL)
88 | {
89 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
90 | return;
91 | }
92 | if (context->width != framebuffer->width || context->height != framebuffer->height)
93 | {
94 | _pr_error_set(PR_ERROR_ARGUMENT_MISMATCH, __FUNCTION__);
95 | return;
96 | }
97 |
98 | // Get iterators
99 | const PRuint num = context->width*context->height;
100 |
101 | pr_color* dst = context->colors;
102 | pr_color* dstEnd = dst + num;
103 |
104 | const pr_pixel* pixels = framebuffer->pixels;
105 | const pr_color* palette = context->colorPalette->colors;
106 |
107 | #ifndef PR_COLOR_BUFFER_24BIT
108 | const pr_color* paletteColor;
109 | #endif
110 |
111 | // Iterate over all pixels
112 | while (dst != dstEnd)
113 | {
114 | #ifdef PR_COLOR_BUFFER_24BIT
115 | *dst = pixels->colorIndex;
116 | #else
117 | paletteColor = (palette + pixels->colorIndex);
118 |
119 | dst->r = paletteColor->r;
120 | dst->g = paletteColor->g;
121 | dst->b = paletteColor->b;
122 | #endif
123 |
124 | ++dst;
125 | ++pixels;
126 | }
127 |
128 | // Show framebuffer on device context ('SetDIBits' only needs a device context when 'DIB_PAL_COLORS' is used)
129 | SetDIBits(NULL, context->bmp, 0, context->height, context->colors, &(context->bmpInfo), DIB_RGB_COLORS);
130 | BitBlt(context->dc, 0, 0, context->width, context->height, context->dcBmp, 0, 0, SRCCOPY);
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/src/platform/win32/context.h:
--------------------------------------------------------------------------------
1 | /*
2 | * context.h (Win32)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_CONTEXT_H
9 | #define PR_CONTEXT_H
10 |
11 |
12 | #include "types.h"
13 | #include "framebuffer.h"
14 | #include "color_palette.h"
15 | #include "color.h"
16 | #include "platform.h"
17 | #include "state_machine.h"
18 |
19 | #include
20 |
21 |
22 | //! Render context structure.
23 | typedef struct pr_context
24 | {
25 | // Win32 objects
26 | HWND wnd;
27 | HDC dc;
28 | HDC dcBmp;
29 | BITMAPINFO bmpInfo;
30 | HBITMAP bmp;
31 |
32 | // Renderer objects
33 | pr_color* colors;
34 | PRuint width;
35 | PRuint height;
36 | pr_color_palette* colorPalette;
37 |
38 | // State objects
39 | pr_state_machine stateMachine;
40 | }
41 | pr_context;
42 |
43 |
44 | extern pr_context* _currentContext;
45 |
46 | //! Creates a new render context for the specified device context.
47 | pr_context* _pr_context_create(const PRcontextdesc* desc, PRuint width, PRuint height);
48 | //! Deletes the specified render context.
49 | void _pr_context_delete(pr_context* context);
50 |
51 | //! Makes the specified context to the current one.
52 | void _pr_context_makecurrent(pr_context* context);
53 |
54 | /**
55 | Presents the specified framebuffer onto the render context.
56 | Errors:
57 | - PR_ERROR_NULL_POINTER : If 'context', 'framebuffer' or 'colorPalette' is null.
58 | - PR_ERROR_ARGUMENT_MISMATCH : If 'context' has another dimension than 'framebuffer'.
59 | */
60 | void _pr_context_present(pr_context* context, const pr_framebuffer* framebuffer);
61 |
62 |
63 | #endif
64 |
--------------------------------------------------------------------------------
/src/plugins/stb/stb_image_write.h:
--------------------------------------------------------------------------------
1 | /* stb_image_write - v0.94 - public domain - http://nothings.org/stb/stb_image_write.h
2 | writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
3 | no warranty implied; use at your own risk
4 |
5 |
6 | Before including,
7 |
8 | #define STB_IMAGE_WRITE_IMPLEMENTATION
9 |
10 | in the file that you want to have the implementation.
11 |
12 | Will probably not work correctly with strict-aliasing optimizations.
13 |
14 |
15 | ABOUT:
16 |
17 | This header file is a library for writing images to C stdio. It could be
18 | adapted to write to memory or a general streaming interface; let me know.
19 |
20 | The PNG output is not optimal; it is 20-50% larger than the file
21 | written by a decent optimizing implementation. This library is designed
22 | for source code compactness and simplicitly, not optimal image file size
23 | or run-time performance.
24 |
25 | USAGE:
26 |
27 | There are three functions, one for each image file format:
28 |
29 | int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
30 | int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
31 | int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
32 |
33 | Each function returns 0 on failure and non-0 on success.
34 |
35 | The functions create an image file defined by the parameters. The image
36 | is a rectangle of pixels stored from left-to-right, top-to-bottom.
37 | Each pixel contains 'comp' channels of data stored interleaved with 8-bits
38 | per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
39 | monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
40 | The *data pointer points to the first byte of the top-left-most pixel.
41 | For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
42 | a row of pixels to the first byte of the next row of pixels.
43 |
44 | PNG creates output files with the same number of components as the input.
45 | The BMP and TGA formats expand Y to RGB in the file format. BMP does not
46 | output alpha.
47 |
48 | PNG supports writing rectangles of data even when the bytes storing rows of
49 | data are not consecutive in memory (e.g. sub-rectangles of a larger image),
50 | by supplying the stride between the beginning of adjacent rows. The other
51 | formats do not. (Thus you cannot write a native-format BMP through the BMP
52 | writer, both because it is in BGR order and because it may have padding
53 | at the end of the line.)
54 | */
55 |
56 | #ifndef INCLUDE_STB_IMAGE_WRITE_H
57 | #define INCLUDE_STB_IMAGE_WRITE_H
58 |
59 | #ifdef __cplusplus
60 | extern "C" {
61 | #endif
62 |
63 | extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
64 | extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
65 | extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
66 |
67 | #ifdef __cplusplus
68 | }
69 | #endif
70 |
71 | #endif//INCLUDE_STB_IMAGE_WRITE_H
72 |
73 | #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
74 |
75 | #include
76 | #include
77 | #include
78 | #include
79 | #include
80 |
81 | typedef unsigned int stbiw_uint32;
82 | typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
83 |
84 | static void writefv(FILE *f, const char *fmt, va_list v)
85 | {
86 | while (*fmt) {
87 | switch (*fmt++) {
88 | case ' ': break;
89 | case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
90 | case '2': { int x = va_arg(v,int); unsigned char b[2];
91 | b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
92 | fwrite(b,2,1,f); break; }
93 | case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
94 | b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
95 | b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
96 | fwrite(b,4,1,f); break; }
97 | default:
98 | assert(0);
99 | return;
100 | }
101 | }
102 | }
103 |
104 | static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
105 | {
106 | unsigned char arr[3];
107 | arr[0] = a, arr[1] = b, arr[2] = c;
108 | fwrite(arr, 3, 1, f);
109 | }
110 |
111 | static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad)
112 | {
113 | unsigned char bg[3] = { 255, 0, 255}, px[3];
114 | stbiw_uint32 zero = 0;
115 | int i,j,k, j_end;
116 |
117 | if (y <= 0)
118 | return;
119 |
120 | if (vdir < 0)
121 | j_end = -1, j = y-1;
122 | else
123 | j_end = y, j = 0;
124 |
125 | for (; j != j_end; j += vdir) {
126 | for (i=0; i < x; ++i) {
127 | unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
128 | if (write_alpha < 0)
129 | fwrite(&d[comp-1], 1, 1, f);
130 | switch (comp) {
131 | case 1:
132 | case 2: write3(f, d[0],d[0],d[0]);
133 | break;
134 | case 4:
135 | if (!write_alpha) {
136 | // composite against pink background
137 | for (k=0; k < 3; ++k)
138 | px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
139 | write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
140 | break;
141 | }
142 | /* FALLTHROUGH */
143 | case 3:
144 | write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
145 | break;
146 | }
147 | if (write_alpha > 0)
148 | fwrite(&d[comp-1], 1, 1, f);
149 | }
150 | fwrite(&zero,scanline_pad,1,f);
151 | }
152 | }
153 |
154 | static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
155 | {
156 | FILE *f;
157 | if (y < 0 || x < 0) return 0;
158 | f = fopen(filename, "wb");
159 | if (f) {
160 | va_list v;
161 | va_start(v, fmt);
162 | writefv(f, fmt, v);
163 | va_end(v);
164 | write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
165 | fclose(f);
166 | }
167 | return f != NULL;
168 | }
169 |
170 | int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
171 | {
172 | int pad = (-x*3) & 3;
173 | return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad,
174 | "11 4 22 4" "4 44 22 444444",
175 | 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
176 | 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
177 | }
178 |
179 | int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
180 | {
181 | int has_alpha = !(comp & 1);
182 | return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
183 | "111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha);
184 | }
185 |
186 | // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
187 | #define stbiw__sbraw(a) ((int *) (a) - 2)
188 | #define stbiw__sbm(a) stbiw__sbraw(a)[0]
189 | #define stbiw__sbn(a) stbiw__sbraw(a)[1]
190 |
191 | #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
192 | #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
193 | #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
194 |
195 | #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
196 | #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
197 | #define stbiw__sbfree(a) ((a) ? free(stbiw__sbraw(a)),0 : 0)
198 |
199 | static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
200 | {
201 | int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
202 | void *p = realloc(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
203 | assert(p);
204 | if (p) {
205 | if (!*arr) ((int *) p)[1] = 0;
206 | *arr = (void *) ((int *) p + 2);
207 | stbiw__sbm(*arr) = m;
208 | }
209 | return *arr;
210 | }
211 |
212 | static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
213 | {
214 | while (*bitcount >= 8) {
215 | stbiw__sbpush(data, (unsigned char) *bitbuffer);
216 | *bitbuffer >>= 8;
217 | *bitcount -= 8;
218 | }
219 | return data;
220 | }
221 |
222 | static int stbiw__zlib_bitrev(int code, int codebits)
223 | {
224 | int res=0;
225 | while (codebits--) {
226 | res = (res << 1) | (code & 1);
227 | code >>= 1;
228 | }
229 | return res;
230 | }
231 |
232 | static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
233 | {
234 | int i;
235 | for (i=0; i < limit && i < 258; ++i)
236 | if (a[i] != b[i]) break;
237 | return i;
238 | }
239 |
240 | static unsigned int stbiw__zhash(unsigned char *data)
241 | {
242 | stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
243 | hash ^= hash << 3;
244 | hash += hash >> 5;
245 | hash ^= hash << 4;
246 | hash += hash >> 17;
247 | hash ^= hash << 25;
248 | hash += hash >> 6;
249 | return hash;
250 | }
251 |
252 | #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
253 | #define stbiw__zlib_add(code,codebits) \
254 | (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
255 | #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
256 | // default huffman tables
257 | #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
258 | #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
259 | #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
260 | #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
261 | #define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))
262 | #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
263 |
264 | #define stbiw__ZHASH 16384
265 |
266 | unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
267 | {
268 | static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
269 | static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
270 | static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
271 | static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
272 | unsigned int bitbuf=0;
273 | int i,j, bitcount=0;
274 | unsigned char *out = NULL;
275 | unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack!
276 | if (quality < 5) quality = 5;
277 |
278 | stbiw__sbpush(out, 0x78); // DEFLATE 32K window
279 | stbiw__sbpush(out, 0x5e); // FLEVEL = 1
280 | stbiw__zlib_add(1,1); // BFINAL = 1
281 | stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
282 |
283 | for (i=0; i < stbiw__ZHASH; ++i)
284 | hash_table[i] = NULL;
285 |
286 | i=0;
287 | while (i < data_len-3) {
288 | // hash next 3 bytes of data to be compressed
289 | int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
290 | unsigned char *bestloc = 0;
291 | unsigned char **hlist = hash_table[h];
292 | int n = stbiw__sbcount(hlist);
293 | for (j=0; j < n; ++j) {
294 | if (hlist[j]-data > i-32768) { // if entry lies within window
295 | int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
296 | if (d >= best) best=d,bestloc=hlist[j];
297 | }
298 | }
299 | // when hash table entry is too long, delete half the entries
300 | if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
301 | memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
302 | stbiw__sbn(hash_table[h]) = quality;
303 | }
304 | stbiw__sbpush(hash_table[h],data+i);
305 |
306 | if (bestloc) {
307 | // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
308 | h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
309 | hlist = hash_table[h];
310 | n = stbiw__sbcount(hlist);
311 | for (j=0; j < n; ++j) {
312 | if (hlist[j]-data > i-32767) {
313 | int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
314 | if (e > best) { // if next match is better, bail on current match
315 | bestloc = NULL;
316 | break;
317 | }
318 | }
319 | }
320 | }
321 |
322 | if (bestloc) {
323 | int d = (int) (data+i - bestloc); // distance back
324 | assert(d <= 32767 && best <= 258);
325 | for (j=0; best > lengthc[j+1]-1; ++j);
326 | stbiw__zlib_huff(j+257);
327 | if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
328 | for (j=0; d > distc[j+1]-1; ++j);
329 | stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
330 | if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
331 | i += best;
332 | } else {
333 | stbiw__zlib_huffb(data[i]);
334 | ++i;
335 | }
336 | }
337 | // write out final bytes
338 | for (;i < data_len; ++i)
339 | stbiw__zlib_huffb(data[i]);
340 | stbiw__zlib_huff(256); // end of block
341 | // pad with 0 bits to byte boundary
342 | while (bitcount)
343 | stbiw__zlib_add(0,1);
344 |
345 | for (i=0; i < stbiw__ZHASH; ++i)
346 | (void) stbiw__sbfree(hash_table[i]);
347 |
348 | {
349 | // compute adler32 on input
350 | unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
351 | int j=0;
352 | while (j < data_len) {
353 | for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
354 | s1 %= 65521, s2 %= 65521;
355 | j += blocklen;
356 | blocklen = 5552;
357 | }
358 | stbiw__sbpush(out, (unsigned char) (s2 >> 8));
359 | stbiw__sbpush(out, (unsigned char) s2);
360 | stbiw__sbpush(out, (unsigned char) (s1 >> 8));
361 | stbiw__sbpush(out, (unsigned char) s1);
362 | }
363 | *out_len = stbiw__sbn(out);
364 | // make returned pointer freeable
365 | memmove(stbiw__sbraw(out), out, *out_len);
366 | return (unsigned char *) stbiw__sbraw(out);
367 | }
368 |
369 | unsigned int stbiw__crc32(unsigned char *buffer, int len)
370 | {
371 | static unsigned int crc_table[256];
372 | unsigned int crc = ~0u;
373 | int i,j;
374 | if (crc_table[1] == 0)
375 | for(i=0; i < 256; i++)
376 | for (crc_table[i]=i, j=0; j < 8; ++j)
377 | crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
378 | for (i=0; i < len; ++i)
379 | crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
380 | return ~crc;
381 | }
382 |
383 | #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
384 | #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
385 | #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
386 |
387 | static void stbiw__wpcrc(unsigned char **data, int len)
388 | {
389 | unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
390 | stbiw__wp32(*data, crc);
391 | }
392 |
393 | static unsigned char stbiw__paeth(int a, int b, int c)
394 | {
395 | int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
396 | if (pa <= pb && pa <= pc) return (unsigned char) a;
397 | if (pb <= pc) return (unsigned char) b;
398 | return (unsigned char) c;
399 | }
400 |
401 | unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
402 | {
403 | int ctype[5] = { -1, 0, 4, 2, 6 };
404 | unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
405 | unsigned char *out,*o, *filt, *zlib;
406 | signed char *line_buffer;
407 | int i,j,k,p,zlen;
408 |
409 | if (stride_bytes == 0)
410 | stride_bytes = x * n;
411 |
412 | filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
413 | line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
414 | for (j=0; j < y; ++j) {
415 | static int mapping[] = { 0,1,2,3,4 };
416 | static int firstmap[] = { 0,1,0,5,6 };
417 | int *mymap = j ? mapping : firstmap;
418 | int best = 0, bestval = 0x7fffffff;
419 | for (p=0; p < 2; ++p) {
420 | for (k= p?best:0; k < 5; ++k) {
421 | int type = mymap[k],est=0;
422 | unsigned char *z = pixels + stride_bytes*j;
423 | for (i=0; i < n; ++i)
424 | switch (type) {
425 | case 0: line_buffer[i] = z[i]; break;
426 | case 1: line_buffer[i] = z[i]; break;
427 | case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
428 | case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
429 | case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
430 | case 5: line_buffer[i] = z[i]; break;
431 | case 6: line_buffer[i] = z[i]; break;
432 | }
433 | for (i=n; i < x*n; ++i) {
434 | switch (type) {
435 | case 0: line_buffer[i] = z[i]; break;
436 | case 1: line_buffer[i] = z[i] - z[i-n]; break;
437 | case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
438 | case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
439 | case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
440 | case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
441 | case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
442 | }
443 | }
444 | if (p) break;
445 | for (i=0; i < x*n; ++i)
446 | est += abs((signed char) line_buffer[i]);
447 | if (est < bestval) { bestval = est; best = k; }
448 | }
449 | }
450 | // when we get here, best contains the filter type, and line_buffer contains the data
451 | filt[j*(x*n+1)] = (unsigned char) best;
452 | memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
453 | }
454 | free(line_buffer);
455 | zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
456 | free(filt);
457 | if (!zlib) return 0;
458 |
459 | // each tag requires 12 bytes of overhead
460 | out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
461 | if (!out) return 0;
462 | *out_len = 8 + 12+13 + 12+zlen + 12;
463 |
464 | o=out;
465 | memcpy(o,sig,8); o+= 8;
466 | stbiw__wp32(o, 13); // header length
467 | stbiw__wptag(o, "IHDR");
468 | stbiw__wp32(o, x);
469 | stbiw__wp32(o, y);
470 | *o++ = 8;
471 | *o++ = (unsigned char) ctype[n];
472 | *o++ = 0;
473 | *o++ = 0;
474 | *o++ = 0;
475 | stbiw__wpcrc(&o,13);
476 |
477 | stbiw__wp32(o, zlen);
478 | stbiw__wptag(o, "IDAT");
479 | memcpy(o, zlib, zlen); o += zlen; free(zlib);
480 | stbiw__wpcrc(&o, zlen);
481 |
482 | stbiw__wp32(o,0);
483 | stbiw__wptag(o, "IEND");
484 | stbiw__wpcrc(&o,0);
485 |
486 | assert(o == out + *out_len);
487 |
488 | return out;
489 | }
490 |
491 | int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
492 | {
493 | FILE *f;
494 | int len;
495 | unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
496 | if (!png) return 0;
497 | f = fopen(filename, "wb");
498 | if (!f) { free(png); return 0; }
499 | fwrite(png, 1, len, f);
500 | fclose(f);
501 | free(png);
502 | return 1;
503 | }
504 | #endif // STB_IMAGE_WRITE_IMPLEMENTATION
505 |
506 | /* Revision history
507 |
508 | 0.94 (2014-05-31)
509 | rename private functions to avoid conflicts with stb_image.h
510 | 0.93 (2014-05-27)
511 | warning fixes
512 | 0.92 (2010-08-01)
513 | casts to unsigned char to fix warnings
514 | 0.91 (2010-07-17)
515 | first public release
516 | 0.90 first internal release
517 | */
518 |
--------------------------------------------------------------------------------
/src/rasterizer/color.h:
--------------------------------------------------------------------------------
1 | /*
2 | * color.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_COLOR_H
9 | #define PR_COLOR_H
10 |
11 |
12 | #include "static_config.h"
13 |
14 |
15 | #ifdef PR_BGR_COLOR_OUTPUT
16 |
17 | #include "color_bgr.h"
18 | typedef pr_color_bgr pr_color;
19 |
20 | #else
21 |
22 | #include "color_rgb.h"
23 | typedef pr_color_rgb pr_color;
24 |
25 | #endif
26 |
27 | #ifdef PR_COLOR_BUFFER_24BIT
28 |
29 | // excpetion in naming conventions for this project:
30 | // with default static configuration, the color index is an 'unsigned char',
31 | // but with 24-bit color buffer, this is from type 'pr_color' structure.
32 | typedef pr_color PRcolorindex;
33 |
34 | #else
35 |
36 | typedef PRubyte PRcolorindex;
37 |
38 | #endif
39 |
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/src/rasterizer/color_bgr.h:
--------------------------------------------------------------------------------
1 | /*
2 | * color_bgr.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_COLOR_BGR_H
9 | #define PR_COLOR_BGR_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | typedef struct pr_color_bgr
16 | {
17 | PRubyte b;
18 | PRubyte g;
19 | PRubyte r;
20 | }
21 | pr_color_bgr;
22 |
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/src/rasterizer/color_palette.c:
--------------------------------------------------------------------------------
1 | /*
2 | * color_palette.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "color_palette.h"
9 | #include "error.h"
10 |
11 |
12 | /*
13 | 8-bit color encoding:
14 |
15 | Bit 7 6 5 4 3 2 1 0
16 | Color R R R G G G B B
17 |
18 | For dithering: scale R and G with 36 and scale B with 85
19 | For color index selection: scale R and G with 32 and B with 64
20 | */
21 | void _pr_color_palette_fill_r3g3b2(pr_color_palette* colorPalette)
22 | {
23 | if (colorPalette == NULL)
24 | {
25 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
26 | return;
27 | }
28 |
29 | pr_color* clr = colorPalette->colors;
30 |
31 | // Color palettes for 3- and 2 bit color components
32 | const PRubyte palette3Bit[8] = { 0, 36, 73, 109, 146, 182, 219, 255 };
33 | const PRubyte palette2Bit[4] = { 0, 85, 170, 255 };
34 |
35 | for (PRubyte r = 0; r < 8; ++r)
36 | {
37 | for (PRubyte g = 0; g < 8; ++g)
38 | {
39 | for (PRubyte b = 0; b < 4; ++b)
40 | {
41 | clr->r = palette3Bit[r];
42 | clr->g = palette3Bit[g];
43 | clr->b = palette2Bit[b];
44 | ++clr;
45 | }
46 | }
47 | }
48 | }
49 |
50 | PRcolorindex _pr_color_to_colorindex(PRubyte r, PRubyte g, PRubyte b)
51 | {
52 | #ifdef PR_COLOR_BUFFER_24BIT
53 |
54 | PRcolorindex color;
55 | color.r = r;
56 | color.g = g;
57 | color.b = b;
58 | return color;
59 |
60 | #else
61 |
62 | /*
63 | No need to crop numbers by bitwise AND 0x07 or 0x03,
64 | since PRubyte cannot exceed the ranges.
65 | */
66 | return
67 | ((r / PR_COLORINDEX_SELECT_RED ) << 5) |
68 | ((g / PR_COLORINDEX_SELECT_GREEN) << 2) |
69 | ( b / PR_COLORINDEX_SELECT_BLUE );
70 |
71 | #endif
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/src/rasterizer/color_palette.h:
--------------------------------------------------------------------------------
1 | /*
2 | * color_palette.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_COLOR_PALETTE_H
9 | #define PR_COLOR_PALETTE_H
10 |
11 |
12 | #include "color.h"
13 |
14 |
15 | #define PR_COLORINDEX_SCALE_RED 36
16 | #define PR_COLORINDEX_SCALE_GREEN 36
17 | #define PR_COLORINDEX_SCALE_BLUE 85
18 |
19 | #define PR_COLORINDEX_SELECT_RED 32
20 | #define PR_COLORINDEX_SELECT_GREEN 32
21 | #define PR_COLORINDEX_SELECT_BLUE 64
22 |
23 |
24 | //! Color palette for 8-bit color indices.
25 | typedef struct pr_color_palette//_r3g3b2
26 | {
27 | pr_color colors[256];
28 | }
29 | pr_color_palette;
30 |
31 |
32 | //! Fills the specified color palette with the encoding R3G3B2.
33 | void _pr_color_palette_fill_r3g3b2(pr_color_palette* colorPalette);
34 |
35 | //! Converts the specified RGB color into a color index with encoding R3G3B2.
36 | PRcolorindex _pr_color_to_colorindex(PRubyte r, PRubyte g, PRubyte b);
37 |
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/src/rasterizer/color_rgb.h:
--------------------------------------------------------------------------------
1 | /*
2 | * color_rgb.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_COLOR_RGB_H
9 | #define PR_COLOR_RGB_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | typedef struct pr_color_rgb
16 | {
17 | PRubyte r;
18 | PRubyte g;
19 | PRubyte b;
20 | }
21 | pr_color_rgb;
22 |
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/src/rasterizer/error.c:
--------------------------------------------------------------------------------
1 | /*
2 | * error.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "error.h"
9 | #include "error_ids.h"
10 |
11 |
12 | static PRenum _error = PR_ERROR_NONE;
13 | static PR_ERROR_HANDLER_PROC _errorHandler = NULL;
14 |
15 | void _pr_error_set(PRenum errorID, const char* info)
16 | {
17 | _error = errorID;
18 | if (_errorHandler != NULL)
19 | _errorHandler(errorID, info);
20 | }
21 |
22 | PRenum _pr_error_get()
23 | {
24 | return _error;
25 | }
26 |
27 | void _pr_error_set_handler(PR_ERROR_HANDLER_PROC errorHandler)
28 | {
29 | _errorHandler = errorHandler;
30 | }
31 |
--------------------------------------------------------------------------------
/src/rasterizer/error.h:
--------------------------------------------------------------------------------
1 | /*
2 | * error.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_ERROR_H
9 | #define PR_ERROR_H
10 |
11 |
12 | #include "types.h"
13 | #include "error_ids.h"
14 |
15 |
16 | #define PR_ERROR(err) _pr_error_set(err, __FUNCTION__)
17 | #define PR_SET_ERROR_FATAL(msg) _pr_error_set(PR_ERROR_FATAL, msg)
18 |
19 |
20 | void _pr_error_set(PRenum errorID, const char* info);
21 | PRenum _pr_error_get();
22 |
23 | //! Sets the error event handler.
24 | void _pr_error_set_handler(PR_ERROR_HANDLER_PROC errorHandler);
25 |
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/src/rasterizer/ext_math.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ext_math.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "ext_math.h"
9 |
10 | #define _USE_MATH_DEFINES
11 | #include
12 |
13 |
14 | // Fast inverse square root from "Quake III Arena"
15 | // See http://en.wikipedia.org/wiki/Fast_inverse_square_root
16 | PRfloat _aprx_inv_sqrt(PRfloat x)
17 | {
18 | float x2 = x * 0.5f;
19 | float y = x;
20 | long i = *(long*)(&y); // Evil floating point bit level hacking
21 | i = 0x5f3759df - (i >> 1); // Magic number
22 | y = *(float*)(&i);
23 | y = y * (1.5f - (x2*y*y)); // 1st iteration
24 | return y;
25 | }
26 |
27 | // Fast and accurate sine approximation
28 | // See http://lab.polygonal.de/?p=205
29 | PRfloat _aprx_sin(PRfloat x)
30 | {
31 | // Always wrap input angle to [-PI .. PI]
32 | if (x < -PR_MATH_PI)
33 | x = fmodf(x - PR_MATH_PI, PR_MATH_PI*2.0f) + PR_MATH_PI;
34 | else if (x > PR_MATH_PI)
35 | x = fmodf(x + PR_MATH_PI, PR_MATH_PI*2.0f) - PR_MATH_PI;
36 |
37 | // Compute sine
38 | float y;
39 |
40 | if (x < 0)
41 | {
42 | y = 1.27323954f * x + 0.405284735f * x*x;
43 |
44 | if (y < 0)
45 | y = 0.225f * (y*(-y) - y) + y;
46 | else
47 | y = 0.225f * (y*y - y) + y;
48 | }
49 | else
50 | {
51 | y = 1.27323954f * x - 0.405284735f * x*x;
52 |
53 | if (y < 0)
54 | y = 0.225f * (y*(-y) - y) + y;
55 | else
56 | y = 0.225f * (y*y - y) + y;
57 | }
58 |
59 | return y;
60 | }
61 |
62 | PRfloat _aprx_cos(PRfloat x)
63 | {
64 | return _aprx_sin(x + PR_MATH_PI*0.5f);
65 | }
66 |
67 | // See http://stackoverflow.com/questions/9411823/fast-log2float-x-implementation-c
68 | PRfloat _aprx_log2(PRfloat x)
69 | {
70 | long* const expPtr = (long*)(&x);
71 | long y = *expPtr;
72 | const long lg2 = ((y >> 23) & 255) - 128;
73 |
74 | y &= ~(255 << 23);
75 | y += 127 << 23;
76 |
77 | *expPtr = y;
78 |
79 | x = ((-1.0f/3) * x + 2) * x - 2.0f/3;
80 |
81 | return (x + lg2);
82 | }
83 |
84 | PRfloat _aprx_log(PRfloat x)
85 | {
86 | return _aprx_log2(x) * 0.69314718f;
87 | }
88 |
89 | PRint _int_log2(PRfloat x)
90 | {
91 | #ifdef PR_FAST_MATH
92 | unsigned long* ix = (unsigned long*)(&x);
93 | unsigned long exp = ((*ix) >> 23) & 0xff;
94 | return (PRint)exp - 127;
95 | #else
96 | int y;
97 | frexpf(x, &y);
98 | return y - 1;
99 | #endif
100 | }
101 |
102 |
--------------------------------------------------------------------------------
/src/rasterizer/ext_math.h:
--------------------------------------------------------------------------------
1 | /*
2 | * ext_math.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_EXT_MATH_H
9 | #define PR_EXT_MATH_H
10 |
11 |
12 | #include "types.h"
13 | #include "static_config.h"
14 | #include "consts.h"
15 |
16 |
17 | #define PR_MIN(a, b) ((a) < (b) ? (a) : (b))
18 | #define PR_MAX(a, b) ((a) > (b) ? (a) : (b))
19 |
20 | #define PR_CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
21 |
22 | #define PR_CLAMP_LARGEST(x, c) if ((x) < (c)) x = c
23 | #define PR_CLAMP_SMALLEST(x, c) if ((x) > (c)) x = c
24 |
25 | #define PR_SIGN(x) (((x) > 0) ? 1 : ((x) < 0) ? -1 : 0)
26 |
27 | #define PR_SQ(x) ((x)*(x))
28 |
29 | #define PR_SWAP(t, a, b) \
30 | { \
31 | t _tmp = a; \
32 | a = b; \
33 | b = _tmp; \
34 | }
35 |
36 | #define PR_SWAP_INT(a, b) \
37 | { \
38 | a ^= b; \
39 | b ^= a; \
40 | a ^= b; \
41 | }
42 |
43 | #ifdef PR_FAST_MATH
44 | # define PR_SIN(x) _aprx_sin(x)
45 | # define PR_COS(x) _aprx_cos(x)
46 | # define PR_TAN(x) (_aprx_sin(x)/_aprx_cos(x))
47 | # define PR_INV_SQRT(x) _aprx_inv_sqrt(x)
48 | # define PR_LOG2(x) _aprx_log2(x)
49 | # define PR_LOG(x) _aprx_log(x)
50 | #else
51 | # define PR_SIN(x) sinf(x)
52 | # define PR_COS(x) cosf(x)
53 | # define PR_TAN(x) tanf(x)
54 | # define PR_INV_SQRT(x) (1.0f / sqrtf(x))
55 | # define PR_LOG2(x) log2f(x)
56 | # define PR_LOG(x) logf(x)
57 | #endif
58 |
59 |
60 | //! Computes an approximated and fast reciprocal square root.
61 | PRfloat _aprx_inv_sqrt(PRfloat x);
62 |
63 | //! Computes an approximated and fast sine.
64 | PRfloat _aprx_sin(PRfloat x);
65 |
66 | //! Computes an approximated and fast cosine.
67 | PRfloat _aprx_cos(PRfloat x);
68 |
69 | //! Computes an approximated and fast logarithm of base 2.
70 | PRfloat _aprx_log2(PRfloat x);
71 |
72 | //! Computes an approximated and fast logarithm of base e (natural logartihm 'ln').
73 | PRfloat _aprx_log(PRfloat x);
74 |
75 | //! Computes the integral value of the logarithm of base 2.
76 | PRint _int_log2(PRfloat x);
77 |
78 |
79 | #endif
80 |
--------------------------------------------------------------------------------
/src/rasterizer/framebuffer.c:
--------------------------------------------------------------------------------
1 | /*
2 | * framebuffer.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "framebuffer.h"
9 | #include "error.h"
10 | #include "helper.h"
11 | #include "state_machine.h"
12 | #include "color_palette.h"
13 |
14 | #include
15 | #include
16 |
17 |
18 | pr_framebuffer* _pr_framebuffer_create(PRuint width, PRuint height)
19 | {
20 | if (width == 0 || height == 0)
21 | {
22 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
23 | return NULL;
24 | }
25 |
26 | // Create framebuffer
27 | pr_framebuffer* frameBuffer = PR_MALLOC(pr_framebuffer);
28 |
29 | frameBuffer->width = width;
30 | frameBuffer->height = height;
31 | frameBuffer->pixels = PR_CALLOC(pr_pixel, width*height);
32 | frameBuffer->scanlinesStart = PR_CALLOC(pr_scaline_side, height);
33 | frameBuffer->scanlinesEnd = PR_CALLOC(pr_scaline_side, height);
34 |
35 | // Initialize framebuffer
36 | memset(frameBuffer->pixels, 0, width*height*sizeof(pr_pixel));
37 |
38 | _pr_ref_add(frameBuffer);
39 |
40 | return frameBuffer;
41 | }
42 |
43 | void _pr_framebuffer_delete(pr_framebuffer* frameBuffer)
44 | {
45 | if (frameBuffer != NULL)
46 | {
47 | _pr_ref_release(frameBuffer);
48 |
49 | PR_FREE(frameBuffer->pixels);
50 | PR_FREE(frameBuffer->scanlinesStart);
51 | PR_FREE(frameBuffer->scanlinesEnd);
52 | PR_FREE(frameBuffer);
53 | }
54 | }
55 |
56 | void _pr_framebuffer_clear(pr_framebuffer* frameBuffer, PRfloat clearDepth, PRbitfield clearFlags)
57 | {
58 | if (frameBuffer != NULL && frameBuffer->pixels != NULL)
59 | {
60 | // Convert depth (32-bit) into pixel depth (16-bit or 8-bit)
61 | PRdepthtype depth = _pr_pixel_write_depth(clearDepth);
62 |
63 | // Get clear color from state machine (and optionally its color index)
64 | PRcolorindex clearColor = PR_STATE_MACHINE.clearColor;
65 |
66 | // Iterate over the entire framebuffer
67 | pr_pixel* dst = frameBuffer->pixels;
68 | pr_pixel* dstEnd = dst + (frameBuffer->width * frameBuffer->height);
69 |
70 | if ((clearFlags & PR_COLOR_BUFFER_BIT) != 0 && (clearFlags & PR_DEPTH_BUFFER_BIT) != 0)
71 | {
72 | while (dst != dstEnd)
73 | {
74 | dst->colorIndex = clearColor;
75 | dst->depth = depth;
76 | ++dst;
77 | }
78 | }
79 | else if ((clearFlags & PR_COLOR_BUFFER_BIT) != 0)
80 | {
81 | while (dst != dstEnd)
82 | {
83 | dst->colorIndex = clearColor;
84 | ++dst;
85 | }
86 | }
87 | else if ((clearFlags & PR_DEPTH_BUFFER_BIT) != 0)
88 | {
89 | while (dst != dstEnd)
90 | {
91 | dst->depth = depth;
92 | ++dst;
93 | }
94 | }
95 | }
96 | else
97 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
98 | }
99 |
100 | void _pr_framebuffer_setup_scanlines(
101 | pr_framebuffer* frameBuffer, pr_scaline_side* sides, pr_raster_vertex start, pr_raster_vertex end)
102 | {
103 | PRint pitch = (PRint)frameBuffer->width;
104 | PRint len = end.y - start.y;
105 |
106 | if (len <= 0)
107 | {
108 | sides[start.y].offset = start.y * pitch + start.x;
109 | return;
110 | }
111 |
112 | // Compute offsets (need doubles for offset for better precision, because the range is larger)
113 | PRdouble offsetStart = (PRdouble)(start.y * pitch + start.x);
114 | PRdouble offsetEnd = (PRdouble)(end.y * pitch + end.x);
115 | PRdouble offsetStep = (offsetEnd - offsetStart) / len;
116 |
117 | PRinterp zStep = (end.z - start.z) / len;
118 | PRinterp uStep = (end.u - start.u) / len;
119 | PRinterp vStep = (end.v - start.v) / len;
120 |
121 | // Fill scanline sides
122 | pr_scaline_side* sidesEnd = &(sides[end.y]);
123 |
124 | for (sides += start.y; sides <= sidesEnd; ++sides)
125 | {
126 | // Setup scanline side
127 | sides->offset = (PRint)(offsetStart + 0.5);
128 | sides->z = start.z;
129 | sides->u = start.u;
130 | sides->v = start.v;
131 |
132 | // Next step
133 | offsetStart += offsetStep;
134 | start.z += zStep;
135 | start.u += uStep;
136 | start.v += vStep;
137 | }
138 | }
139 |
140 |
--------------------------------------------------------------------------------
/src/rasterizer/framebuffer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * framebuffer.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_FRAMEBUFFER_H
9 | #define PR_FRAMEBUFFER_H
10 |
11 |
12 | #include "pixel.h"
13 | #include "enums.h"
14 | #include "raster_vertex.h"
15 |
16 |
17 | //! Raster scanline side structure
18 | typedef struct pr_scaline_side
19 | {
20 | PRint offset; //!< Pixel offset in framebuffer
21 | PRinterp z;
22 | PRinterp u;
23 | PRinterp v;
24 | }
25 | pr_scaline_side;
26 |
27 | //! Framebuffer structure
28 | typedef struct pr_framebuffer
29 | {
30 | PRuint width;
31 | PRuint height;
32 | #ifdef PR_MERGE_COLOR_AND_DEPTH_BUFFERS
33 | pr_pixel* pixels;
34 | #else
35 | PRubyte* colors;
36 | PRdepthtype depths;
37 | #endif
38 | pr_scaline_side* scanlinesStart; //!< Start offsets to scanlines
39 | pr_scaline_side* scanlinesEnd; //!< End offsets to scanlines
40 | }
41 | pr_framebuffer;
42 |
43 |
44 | pr_framebuffer* _pr_framebuffer_create(PRuint width, PRuint height);
45 | void _pr_framebuffer_delete(pr_framebuffer* frameBuffer);
46 |
47 | void _pr_framebuffer_clear(pr_framebuffer* frameBuffer, PRfloat clearDepth, PRbitfield clearFlags);
48 |
49 | //! Sets the start and end offsets of the specified scanlines.
50 | void _pr_framebuffer_setup_scanlines(
51 | pr_framebuffer* frameBuffer, pr_scaline_side* sides, pr_raster_vertex start, pr_raster_vertex end
52 | );
53 |
54 | PR_INLINE void _pr_framebuffer_plot(pr_framebuffer* frameBuffer, PRuint x, PRuint y, PRcolorindex colorIndex)
55 | {
56 | #ifdef PR_MERGE_COLOR_AND_DEPTH_BUFFERS
57 | frameBuffer->pixels[y * frameBuffer->width + x].colorIndex = colorIndex;
58 | #else
59 | frameBuffer->colors[y * frameBuffer->width + x] = colorIndex;
60 | #endif
61 | }
62 |
63 |
64 | #endif
65 |
--------------------------------------------------------------------------------
/src/rasterizer/global_state.c:
--------------------------------------------------------------------------------
1 | /*
2 | * globa_state.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "global_state.h"
9 | #include "static_config.h"
10 | #include "error.h"
11 | #include "render.h"
12 |
13 |
14 | pr_global_state _globalState;
15 |
16 | #define _IMM_VERTICES _globalState.immModeVertexBuffer.vertices
17 | #define _IMM_CUR_VERTEX _IMM_VERTICES[_globalState.immModeVertCounter]
18 |
19 |
20 | void _pr_global_state_init()
21 | {
22 | _pr_texture_singular_init(&(_globalState.singularTexture));
23 |
24 | // Initialize immediate mode
25 | _pr_vertexbuffer_singular_init(&(_globalState.immModeVertexBuffer), PR_NUM_IMMEDIATE_VERTICES);
26 | _globalState.immModeActive = PR_FALSE;
27 | _globalState.immModeVertCounter = 0;
28 | _globalState.immModePrimitives = PR_POINTS;
29 | }
30 |
31 | void _pr_global_state_release()
32 | {
33 | _pr_texture_singular_clear(&(_globalState.singularTexture));
34 | _pr_vertexbuffer_singular_clear(&(_globalState.immModeVertexBuffer));
35 | }
36 |
37 | static void _immediate_mode_flush()
38 | {
39 | if (_globalState.immModeVertCounter == 0)
40 | return;
41 |
42 | // Draw current vertex buffer
43 | switch (_globalState.immModePrimitives)
44 | {
45 | case PR_POINTS:
46 | _pr_render_points(_globalState.immModeVertCounter, 0, &(_globalState.immModeVertexBuffer));
47 | break;
48 |
49 | case PR_LINES:
50 | _pr_render_lines(_globalState.immModeVertCounter, 0, &(_globalState.immModeVertexBuffer));
51 | break;
52 | case PR_LINE_STRIP:
53 | _pr_render_line_strip(_globalState.immModeVertCounter, 0, &(_globalState.immModeVertexBuffer));
54 | break;
55 | case PR_LINE_LOOP:
56 | _pr_render_line_loop(_globalState.immModeVertCounter, 0, &(_globalState.immModeVertexBuffer));
57 | break;
58 |
59 | case PR_TRIANGLES:
60 | _pr_render_triangles(_globalState.immModeVertCounter, 0, &(_globalState.immModeVertexBuffer));
61 | break;
62 | case PR_TRIANGLE_STRIP:
63 | _pr_render_triangle_strip(_globalState.immModeVertCounter, 0, &(_globalState.immModeVertexBuffer));
64 | break;
65 | case PR_TRIANGLE_FAN:
66 | _pr_render_triangle_fan(_globalState.immModeVertCounter, 0, &(_globalState.immModeVertexBuffer));
67 | break;
68 |
69 | default:
70 | PR_ERROR(PR_ERROR_INVALID_ARGUMENT);
71 | break;
72 | }
73 |
74 | // Reset vertex counter
75 | _globalState.immModeVertCounter = 0;
76 | }
77 |
78 | void _pr_immediate_mode_begin(PRenum primitives)
79 | {
80 | if (_globalState.immModeActive)
81 | {
82 | PR_ERROR(PR_ERROR_INVALID_STATE);
83 | return;
84 | }
85 | if (primitives < PR_POINTS || primitives > PR_TRIANGLE_FAN)
86 | {
87 | PR_ERROR(PR_ERROR_INVALID_ARGUMENT);
88 | return;
89 | }
90 |
91 | // Store primitive type and reset vertex counter
92 | _globalState.immModeActive = PR_TRUE;
93 | _globalState.immModePrimitives = primitives;
94 | _globalState.immModeVertCounter = 0;
95 | }
96 |
97 | void _pr_immediate_mode_end()
98 | {
99 | if (!_globalState.immModeActive)
100 | {
101 | PR_ERROR(PR_ERROR_INVALID_STATE);
102 | return;
103 | }
104 |
105 | // Draw vertex buffer with current previously selected primitive
106 | _immediate_mode_flush();
107 |
108 | _globalState.immModeActive = PR_FALSE;
109 | }
110 |
111 | void _pr_immediate_mode_texcoord(PRfloat u, PRfloat v)
112 | {
113 | // Store texture coordinate for current vertex
114 | _IMM_CUR_VERTEX.texCoord.x = u;
115 | _IMM_CUR_VERTEX.texCoord.y = v;
116 | }
117 |
118 | void _pr_immediate_mode_vertex(PRfloat x, PRfloat y, PRfloat z, PRfloat w)
119 | {
120 | // Store vertex coordinate for current vertex
121 | _IMM_CUR_VERTEX.coord.x = x;
122 | _IMM_CUR_VERTEX.coord.y = y;
123 | _IMM_CUR_VERTEX.coord.z = z;
124 | _IMM_CUR_VERTEX.coord.w = w;
125 |
126 | // Count to next vertex
127 | ++_globalState.immModeVertCounter;
128 |
129 | // Check if limit is exceeded
130 | if (_globalState.immModeVertCounter >= PR_NUM_IMMEDIATE_VERTICES)
131 | _immediate_mode_flush();
132 |
133 | switch (_globalState.immModePrimitives)
134 | {
135 | case PR_TRIANGLES:
136 | if ( _globalState.immModeVertCounter + 3 >= PR_NUM_IMMEDIATE_VERTICES &&
137 | _globalState.immModeVertCounter % 3 == 0 )
138 | {
139 | _immediate_mode_flush();
140 | }
141 | break;
142 | }
143 | }
144 |
145 |
--------------------------------------------------------------------------------
/src/rasterizer/global_state.h:
--------------------------------------------------------------------------------
1 | /*
2 | * globa_state.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_GLOBAL_STATE_H
9 | #define PR_GLOBAL_STATE_H
10 |
11 |
12 | #include "texture.h"
13 | #include "vertexbuffer.h"
14 |
15 |
16 | #define PR_SINGULAR_TEXTURE _globalState.singularTexture
17 | #define PR_SINGULAR_VERTEXBUFFER _globalState.singularVertexBuffer
18 |
19 | // Number of vertices for the vertex buffer of the immediate draw mode (prBegin/prEnd)
20 | #define PR_NUM_IMMEDIATE_VERTICES 32
21 |
22 |
23 | typedef struct pr_global_state
24 | {
25 | pr_texture singularTexture; // Texture with single color
26 |
27 | // Immediate mode
28 | pr_vertexbuffer immModeVertexBuffer;
29 | PRboolean immModeActive;
30 | PRsizei immModeVertCounter;
31 | PRenum immModePrimitives;
32 | }
33 | pr_global_state;
34 |
35 |
36 | //! Global render engine state.
37 | extern pr_global_state _globalState;
38 |
39 |
40 | void _pr_global_state_init();
41 | void _pr_global_state_release();
42 |
43 | void _pr_immediate_mode_begin(PRenum primitives);
44 | void _pr_immediate_mode_end();
45 |
46 | void _pr_immediate_mode_texcoord(PRfloat u, PRfloat v);
47 | void _pr_immediate_mode_vertex(PRfloat x, PRfloat y, PRfloat z, PRfloat w);
48 |
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/src/rasterizer/helper.h:
--------------------------------------------------------------------------------
1 | /*
2 | * helper.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_HELPER_H
9 | #define PR_HELPER_H
10 |
11 |
12 | #define PR_MALLOC(t) (t*)malloc(sizeof(t))
13 | #define PR_CALLOC(t, n) (t*)calloc(n, sizeof(t))
14 |
15 | #define PR_FREE(m) \
16 | if ((m) != NULL) \
17 | { \
18 | free(m); \
19 | m = NULL; \
20 | }
21 |
22 | #define PR_ZERO_MEMORY(m) memset(&m, 0, sizeof(m))
23 |
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/src/rasterizer/image.c:
--------------------------------------------------------------------------------
1 | /*
2 | * image.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "image.h"
9 | #include "error.h"
10 | #include "helper.h"
11 | #include "static_config.h"
12 | #include "color_palette.h"
13 |
14 | #ifdef PR_INCLUDE_PLUGINS
15 | # define STB_IMAGE_IMPLEMENTATION
16 | # include "plugins/stb/stb_image.h"
17 | #endif
18 |
19 |
20 | pr_image* _pr_image_load_from_file(const char* filename)
21 | {
22 | if (filename == NULL)
23 | {
24 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
25 | return NULL;
26 | }
27 | if (*filename == '\0')
28 | {
29 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
30 | return NULL;
31 | }
32 |
33 | // Create image and load data from file
34 | pr_image* image = PR_MALLOC(pr_image);
35 |
36 | #ifdef PR_INCLUDE_PLUGINS
37 |
38 | image->width = 0;
39 | image->height = 0;
40 | image->format = 0;
41 | image->colors = stbi_load(filename, &(image->width), &(image->height), &(image->format), 3);
42 | image->defFree = PR_FALSE;
43 |
44 | if (image->colors == NULL)
45 | {
46 |
47 | #endif
48 |
49 | image->width = 1;
50 | image->height = 1;
51 | image->format = 3;
52 | image->colors = PR_CALLOC(PRubyte, 3);
53 | image->defFree = PR_TRUE;
54 |
55 | image->colors[0] = 0;
56 | image->colors[1] = 0;
57 | image->colors[2] = 0;
58 |
59 | #ifdef PR_INCLUDE_PLUGINS
60 |
61 | }
62 |
63 | #endif
64 |
65 | return image;
66 | }
67 |
68 | pr_image* _pr_image_create(PRint width, PRint height, PRint format)
69 | {
70 | if (width <= 0 || height <= 0 || format < 1 || format > 4)
71 | {
72 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
73 | return NULL;
74 | }
75 |
76 | // Create image
77 | pr_image* image = PR_MALLOC(pr_image);
78 |
79 | image->width = width;
80 | image->height = height;
81 | image->format = format;
82 | image->defFree = PR_TRUE;
83 | image->colors = PR_CALLOC(PRubyte, width*height*format);
84 |
85 | return image;
86 | }
87 |
88 | void _pr_image_delete(pr_image* image)
89 | {
90 | if (image != NULL)
91 | {
92 | if (image->colors != NULL)
93 | {
94 | #ifdef PR_INCLUDE_PLUGINS
95 | if (!image->defFree)
96 | {
97 | stbi_image_free(image->colors);
98 | }
99 | else
100 | #endif
101 | {
102 | //error???
103 | //PR_FREE(image->colors);
104 | }
105 | }
106 | PR_FREE(image);
107 | }
108 | }
109 |
110 |
111 | #define PIXEL(x, y) imageBuffer[(y)*imageWidth+(x)]
112 | #define DITHER(c, s)
113 |
114 | /*
115 | This function implements the "Floyd-Steinberg" dithering algorithm.
116 | The distribution pattern around the pixel 'px' is:
117 | [ px ] [7/16]
118 | [3/16] [5/16] [1/16]
119 | */
120 | static void _dither_color(PRint* buffer, PRint x, PRint y, PRint comp, PRint width, PRint height, PRint scale)
121 | {
122 | #define COLOR(x, y) buffer[((y)*width + (x))*3 + comp]
123 |
124 | // Get old and new color
125 | int oldPixel = COLOR(x, y);
126 | int newPixel = (oldPixel/scale)*scale;
127 |
128 | // Write final color
129 | COLOR(x, y) = newPixel;
130 |
131 | // Get quantification error
132 | int quantErr = oldPixel - newPixel;
133 |
134 | // Apply dithering distribution
135 | if (x + 1 < width)
136 | COLOR(x + 1, y ) += quantErr*7/16;
137 | if (x > 0 && y + 1 < height)
138 | COLOR(x - 1, y + 1) += quantErr*3/16;
139 | if (y + 1 < height)
140 | COLOR(x , y + 1) += quantErr*5/16;
141 | if (x + 1 < width && y + 1 < height)
142 | COLOR(x + 1, y + 1) += quantErr*1/16;
143 |
144 | #undef COLOR
145 | }
146 |
147 | void _pr_image_color_to_colorindex(PRcolorindex* dstColors, const pr_image* srcImage, PRboolean dither)
148 | {
149 | // Validate and map input parameters
150 | if (dstColors == NULL || srcImage == NULL)
151 | {
152 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
153 | return;
154 | }
155 |
156 | const PRint width = srcImage->width;
157 | const PRint height = srcImage->height;
158 | const PRint format = srcImage->format;
159 |
160 | if (width <= 0 || height <= 0 || format < 1 || format > 4)
161 | {
162 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
163 | return;
164 | }
165 |
166 | const PRubyte* src = srcImage->colors;
167 |
168 | const PRuint numPixels = width*height;
169 |
170 | if (dither != PR_FALSE)
171 | {
172 | // Fill temporary integer buffer
173 | const PRuint numColors = width*height*3;
174 | PRint* buffer = PR_CALLOC(PRint, numColors);
175 |
176 | if (format < 3)
177 | {
178 | // Copy gray scale image into buffer
179 | for (PRuint i = 0, j = 0; i < numColors; i += 3, j += format)
180 | {
181 | buffer[i ] = src[j];
182 | buffer[i + 1] = src[j];
183 | buffer[i + 2] = src[j];
184 | }
185 | }
186 | else
187 | {
188 | // Copy RGB image into buffer
189 | for (PRuint i = 0, j = 0; i < numColors; i += 3, j += format)
190 | {
191 | buffer[i ] = (PRint)src[j ];
192 | buffer[i + 1] = (PRint)src[j + 1];
193 | buffer[i + 2] = (PRint)src[j + 2];
194 | }
195 | }
196 |
197 | // Apply dithering to buffer
198 | for (PRint y = 0; y < height; ++y)
199 | {
200 | for (PRint x = 0; x < width; ++x)
201 | {
202 | _dither_color(buffer, x, y, 0, width, height, PR_COLORINDEX_SCALE_RED );
203 | _dither_color(buffer, x, y, 1, width, height, PR_COLORINDEX_SCALE_GREEN);
204 | _dither_color(buffer, x, y, 2, width, height, PR_COLORINDEX_SCALE_BLUE );
205 | }
206 | }
207 |
208 | // Finally convert buffer to color index
209 | for (PRuint i = 0, j = 0; i < numPixels; ++i, j += 3)
210 | dstColors[i] = _pr_color_to_colorindex(buffer[j], buffer[j + 1], buffer[j + 2]);
211 |
212 | // Delete temporary buffer
213 | PR_FREE(buffer);
214 | }
215 | else
216 | {
217 | // Copy image data
218 | if (format < 3)
219 | {
220 | // Copy gray scale image into color index
221 | PRubyte gray;
222 |
223 | for (PRuint i = 0, j = 0; i < numPixels; ++i, j += format)
224 | {
225 | gray = src[j];
226 | dstColors[i] = _pr_color_to_colorindex(gray, gray, gray);
227 | }
228 | }
229 | else
230 | {
231 | // Copy RGB image into color index
232 | for (PRuint i = 0, j = 0; i < numPixels; ++i, j += format)
233 | dstColors[i] = _pr_color_to_colorindex(src[j], src[j + 1], src[j + 2]);
234 | }
235 | }
236 | }
237 |
238 |
--------------------------------------------------------------------------------
/src/rasterizer/image.h:
--------------------------------------------------------------------------------
1 | /*
2 | * image.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_IMAGE_H
9 | #define PR_IMAGE_H
10 |
11 |
12 | #include "types.h"
13 | #include "color.h"
14 |
15 |
16 | //! Simple 2D image.
17 | typedef struct pr_image
18 | {
19 | PRint width; //!< Image width.
20 | PRint height; //!< Image height.
21 | PRint format; //!< Color format (1, 2, 3 or 4).
22 | PRboolean defFree; //!< True if colors will be deleted with default method.
23 | PRubyte* colors; //!< Colors array.
24 | }
25 | pr_image;
26 |
27 |
28 | //! Loads an RGB image from file.
29 | pr_image* _pr_image_load_from_file(const char* filename);
30 | /**
31 | Creates a new image.
32 | \param[in] width Specifies the image width. This must be greather than 0.
33 | \param[in] height Specifies the image width. This must be greather than 0.
34 | \param[in] format Specifies the image format. This must be 1, 2, 3 or 4.
35 | */
36 | pr_image* _pr_image_create(PRint width, PRint height, PRint format);
37 | //! Deletes the specifies image.
38 | void _pr_image_delete(pr_image* image);
39 |
40 | /**
41 | Converts the specified 24-bit RGB colors 'src' into 8-bit color indices 'dst'.
42 | \param[out] dst Pointer to the destination color indices.
43 | This must already be allocated with the specified size: width*height*sizeof(PRubyte)!
44 | \param[in] src Pointer to the source colors.
45 | \param[in] width Specifies the image width.
46 | \param[in] height Specifies the image height.
47 | \param[in] format Specifies the source color format. Must be 1, 2, 3 or 4.
48 | \param[in] dither Specifies whether the image is to be converted with or without dithering.
49 | */
50 | void _pr_image_color_to_colorindex(PRcolorindex* dstColors, const pr_image* srcImage, PRboolean dither);
51 |
52 |
53 | #endif
54 |
--------------------------------------------------------------------------------
/src/rasterizer/indexbuffer.c:
--------------------------------------------------------------------------------
1 | /*
2 | * indexbuffer.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "indexbuffer.h"
9 | #include "helper.h"
10 | #include "error.h"
11 | #include "state_machine.h"
12 |
13 | #include
14 |
15 |
16 | pr_indexbuffer* _pr_indexbuffer_create()
17 | {
18 | pr_indexbuffer* indexBuffer = PR_MALLOC(pr_indexbuffer);
19 |
20 | indexBuffer->numIndices = 0;
21 | indexBuffer->indices = NULL;
22 |
23 | _pr_ref_add(indexBuffer);
24 |
25 | return indexBuffer;
26 | }
27 |
28 | void _pr_indexbuffer_delete(pr_indexbuffer* indexBuffer)
29 | {
30 | if (indexBuffer != NULL)
31 | {
32 | _pr_ref_release(indexBuffer);
33 |
34 | PR_FREE(indexBuffer->indices);
35 | PR_FREE(indexBuffer);
36 | }
37 | }
38 |
39 | static void _indexbuffer_resize(pr_indexbuffer* indexBuffer, PRushort numIndices)
40 | {
41 | // Check if index buffer must be reallocated
42 | if (indexBuffer->indices == NULL || indexBuffer->numIndices != numIndices)
43 | {
44 | // Create new index buffer data
45 | PR_FREE(indexBuffer->indices);
46 |
47 | indexBuffer->numIndices = numIndices;
48 | indexBuffer->indices = PR_CALLOC(PRushort, numIndices);
49 | }
50 | }
51 |
52 | void _pr_indexbuffer_data(pr_indexbuffer* indexBuffer, const PRushort* indices, PRushort numIndices)
53 | {
54 | if (indexBuffer == NULL || indices == NULL)
55 | {
56 | PR_ERROR(PR_ERROR_NULL_POINTER);
57 | return;
58 | }
59 |
60 | _indexbuffer_resize(indexBuffer, numIndices);
61 |
62 | // Fill index buffer
63 | while (numIndices-- > 0)
64 | indexBuffer->indices[numIndices] = indices[numIndices];
65 | }
66 |
67 | void _pr_indexbuffer_data_from_file(pr_indexbuffer* indexBuffer, PRsizei* numIndices, FILE* file)
68 | {
69 | if (indexBuffer == NULL || numIndices == NULL || file == NULL)
70 | {
71 | PR_ERROR(PR_ERROR_NULL_POINTER);
72 | return;
73 | }
74 |
75 | // Read number of indices
76 | PRushort numInd = 0;
77 | fread(&numInd, sizeof(PRushort), 1, file);
78 | *numIndices = (PRsizei)numInd;
79 |
80 | _indexbuffer_resize(indexBuffer, *numIndices);
81 |
82 | // Read all indices
83 | fread(indexBuffer->indices, sizeof(PRushort), *numIndices, file);
84 | }
85 |
86 |
--------------------------------------------------------------------------------
/src/rasterizer/indexbuffer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * indexbuffer.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_INDEXBUFFER_H
9 | #define PR_INDEXBUFFER_H
10 |
11 |
12 | #include "types.h"
13 |
14 | #include
15 |
16 |
17 | typedef struct pr_indexbuffer
18 | {
19 | PRushort numIndices;
20 | PRushort* indices;
21 | }
22 | pr_indexbuffer;
23 |
24 |
25 | pr_indexbuffer* _pr_indexbuffer_create();
26 | void _pr_indexbuffer_delete(pr_indexbuffer* indexBuffer);
27 |
28 | void _pr_indexbuffer_data(pr_indexbuffer* indexBuffer, const PRushort* indices, PRushort numIndices);
29 | void _pr_indexbuffer_data_from_file(pr_indexbuffer* indexBuffer, PRsizei* numIndices, FILE* file);
30 |
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/src/rasterizer/matrix4.c:
--------------------------------------------------------------------------------
1 | /*
2 | * matrix4.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "matrix4.h"
9 | #include "error.h"
10 | #include "ext_math.h"
11 |
12 | #include
13 | #include
14 |
15 |
16 | void _pr_matrix_load_identity(pr_matrix4* matrix)
17 | {
18 | matrix->m[0][0] = 1.0f; matrix->m[1][0] = 0.0f; matrix->m[2][0] = 0.0f; matrix->m[3][0] = 0.0f;
19 | matrix->m[0][1] = 0.0f; matrix->m[1][1] = 1.0f; matrix->m[2][1] = 0.0f; matrix->m[3][1] = 0.0f;
20 | matrix->m[0][2] = 0.0f; matrix->m[1][2] = 0.0f; matrix->m[2][2] = 1.0f; matrix->m[3][2] = 0.0f;
21 | matrix->m[0][3] = 0.0f; matrix->m[1][3] = 0.0f; matrix->m[2][3] = 0.0f; matrix->m[3][3] = 1.0f;
22 | }
23 |
24 | void _pr_matrix_copy(pr_matrix4* dst, const pr_matrix4* src)
25 | {
26 | memcpy(dst, src, sizeof(pr_matrix4));
27 | }
28 |
29 | void _pr_matrix_mul_float3(PRfloat* result, const pr_matrix4* lhs, const PRfloat* rhs)
30 | {
31 | result[0] = (lhs->m[0][0] * rhs[0]) + (lhs->m[1][0] * rhs[1]) + (lhs->m[2][0] * rhs[2]) + lhs->m[3][0];
32 | result[1] = (lhs->m[0][1] * rhs[0]) + (lhs->m[1][1] * rhs[1]) + (lhs->m[2][1] * rhs[2]) + lhs->m[3][1];
33 | result[2] = (lhs->m[0][2] * rhs[0]) + (lhs->m[1][2] * rhs[1]) + (lhs->m[2][2] * rhs[2]) + lhs->m[3][2];
34 | }
35 |
36 | void _pr_matrix_mul_float4(PRfloat* result, const pr_matrix4* lhs, const PRfloat* rhs)
37 | {
38 | result[0] = (lhs->m[0][0] * rhs[0]) + (lhs->m[1][0] * rhs[1]) + (lhs->m[2][0] * rhs[2]) + (lhs->m[3][0] * rhs[3]);
39 | result[1] = (lhs->m[0][1] * rhs[0]) + (lhs->m[1][1] * rhs[1]) + (lhs->m[2][1] * rhs[2]) + (lhs->m[3][1] * rhs[3]);
40 | result[2] = (lhs->m[0][2] * rhs[0]) + (lhs->m[1][2] * rhs[1]) + (lhs->m[2][2] * rhs[2]) + (lhs->m[3][2] * rhs[3]);
41 | result[3] = (lhs->m[0][3] * rhs[0]) + (lhs->m[1][3] * rhs[1]) + (lhs->m[2][3] * rhs[2]) + (lhs->m[3][3] * rhs[3]);
42 | }
43 |
44 | void _pr_matrix_mul_vector3(pr_vector3* result, const pr_matrix4* lhs, const pr_vector3* rhs)
45 | {
46 | _pr_matrix_mul_float3((PRfloat*)result, lhs, (const PRfloat*)rhs);
47 | }
48 |
49 | void _pr_matrix_mul_vector4(pr_vector4* result, const pr_matrix4* lhs, const pr_vector4* rhs)
50 | {
51 | _pr_matrix_mul_float4((PRfloat*)result, lhs, (const PRfloat*)rhs);
52 | }
53 |
54 | void _pr_matrix_mul_matrix(pr_matrix4* result, const pr_matrix4* lhs, const pr_matrix4* rhs)
55 | {
56 | PRfloat* m3 = &(result->m[0][0]);
57 | const PRfloat* m1 = &(lhs->m[0][0]);
58 | const PRfloat* m2 = &(rhs->m[0][0]);
59 |
60 | m3[ 0] = m1[0]*m2[ 0] + m1[4]*m2[ 1] + m1[ 8]*m2[ 2] + m1[12]*m2[ 3];
61 | m3[ 1] = m1[1]*m2[ 0] + m1[5]*m2[ 1] + m1[ 9]*m2[ 2] + m1[13]*m2[ 3];
62 | m3[ 2] = m1[2]*m2[ 0] + m1[6]*m2[ 1] + m1[10]*m2[ 2] + m1[14]*m2[ 3];
63 | m3[ 3] = m1[3]*m2[ 0] + m1[7]*m2[ 1] + m1[11]*m2[ 2] + m1[15]*m2[ 3];
64 |
65 | m3[ 4] = m1[0]*m2[ 4] + m1[4]*m2[ 5] + m1[ 8]*m2[ 6] + m1[12]*m2[ 7];
66 | m3[ 5] = m1[1]*m2[ 4] + m1[5]*m2[ 5] + m1[ 9]*m2[ 6] + m1[13]*m2[ 7];
67 | m3[ 6] = m1[2]*m2[ 4] + m1[6]*m2[ 5] + m1[10]*m2[ 6] + m1[14]*m2[ 7];
68 | m3[ 7] = m1[3]*m2[ 4] + m1[7]*m2[ 5] + m1[11]*m2[ 6] + m1[15]*m2[ 7];
69 |
70 | m3[ 8] = m1[0]*m2[ 8] + m1[4]*m2[ 9] + m1[ 8]*m2[10] + m1[12]*m2[11];
71 | m3[ 9] = m1[1]*m2[ 8] + m1[5]*m2[ 9] + m1[ 9]*m2[10] + m1[13]*m2[11];
72 | m3[10] = m1[2]*m2[ 8] + m1[6]*m2[ 9] + m1[10]*m2[10] + m1[14]*m2[11];
73 | m3[11] = m1[3]*m2[ 8] + m1[7]*m2[ 9] + m1[11]*m2[10] + m1[15]*m2[11];
74 |
75 | m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[ 8]*m2[14] + m1[12]*m2[15];
76 | m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[ 9]*m2[14] + m1[13]*m2[15];
77 | m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
78 | m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
79 | }
80 |
81 | void _pr_matrix_translate(pr_matrix4* result, PRfloat x, PRfloat y, PRfloat z)
82 | {
83 | PRfloat* m = &(result->m[0][0]);
84 | m[12] += ( m[0]*x + m[4]*y + m[ 8]*z );
85 | m[13] += ( m[1]*x + m[5]*y + m[ 9]*z );
86 | m[14] += ( m[2]*x + m[6]*y + m[10]*z );
87 | m[15] += ( m[3]*x + m[7]*y + m[11]*z );
88 | }
89 |
90 | void _pr_matrix_rotate(pr_matrix4* result, PRfloat x, PRfloat y, PRfloat z, PRfloat angle)
91 | {
92 | // Normalize rotation vector
93 | PRfloat len = x*x + y*y + z*z;
94 |
95 | if (len != 0.0f && len != 1.0f)
96 | {
97 | PRfloat invLen = PR_INV_SQRT(len);
98 | x *= invLen;
99 | y *= invLen;
100 | z *= invLen;
101 | }
102 |
103 | // Pre-compute rotation values
104 | const PRfloat s = PR_SIN(angle);
105 | const PRfloat c = PR_COS(angle);
106 | const PRfloat cc = 1.0f - c;
107 |
108 | // Setup rotation matrix
109 | pr_matrix4 rhs;
110 | PRfloat* m = &(rhs.m[0][0]);
111 |
112 | m[0] = x*x*cc + c; m[4] = x*y*cc - z*s; m[ 8] = x*z*cc + y*s; m[12] = 0.0f;
113 | m[1] = y*x*cc + z*s; m[5] = y*y*cc + c; m[ 9] = y*z*cc - x*s; m[13] = 0.0f;
114 | m[2] = x*z*cc - y*s; m[6] = y*z*cc + x*s; m[10] = z*z*cc + c; m[14] = 0.0f;
115 | m[3] = 0.0f; m[7] = 0.0f; m[11] = 0.0f; m[15] = 1.0f;
116 |
117 | // Multiply input matrix (lhs) with rotation matrix (rhs)
118 | pr_matrix4 lhs;
119 | _pr_matrix_copy(&lhs, result);
120 |
121 | _pr_matrix_mul_matrix(result, &lhs, &rhs);
122 | }
123 |
124 | void _pr_matrix_scale(pr_matrix4* result, PRfloat x, PRfloat y, PRfloat z)
125 | {
126 | PRfloat* m = &(result->m[0][0]);
127 | m[0] *= x; m[1] *= x; m[ 2] *= x; m[ 3] *= x;
128 | m[4] *= y; m[5] *= y; m[ 6] *= y; m[ 7] *= y;
129 | m[8] *= z; m[9] *= z; m[10] *= z; m[11] *= z;
130 | }
131 |
132 | void _pr_matrix_build_perspective(pr_matrix4* result, PRfloat aspectRatio, PRfloat nearPlane, PRfloat farPlane, PRfloat fov)
133 | {
134 | if (result == NULL)
135 | {
136 | PR_ERROR(PR_ERROR_NULL_POINTER);
137 | return;
138 | }
139 |
140 | const PRfloat h = 1.0f / tanf(fov * 0.5f);
141 | const PRfloat w = h / aspectRatio;
142 |
143 | PRfloat* m = &(result->m[0][0]);
144 |
145 | m[ 0] = w;
146 | m[ 1] = 0.0f;
147 | m[ 2] = 0.0f;
148 | m[ 3] = 0.0f;
149 |
150 | m[ 4] = 0.0f;
151 | m[ 5] = h;
152 | m[ 6] = 0.0f;
153 | m[ 7] = 0.0f;
154 |
155 | m[ 8] = 0.0f;
156 | m[ 9] = 0.0f;
157 | m[10] = farPlane/(farPlane - nearPlane);
158 | m[11] = 1.0f;
159 |
160 | m[12] = 0.0f;
161 | m[13] = 0.0f;
162 | m[14] = -(farPlane*nearPlane)/(farPlane - nearPlane);
163 | m[15] = 0.0f;
164 | }
165 |
166 | void _pr_matrix_build_orthogonal(pr_matrix4* result, PRfloat width, PRfloat height, PRfloat nearPlane, PRfloat farPlane)
167 | {
168 | if (result == NULL)
169 | {
170 | PR_ERROR(PR_ERROR_NULL_POINTER);
171 | return;
172 | }
173 |
174 | PRfloat* m = &(result->m[0][0]);
175 |
176 | m[ 0] = 2.0f / width;
177 | m[ 1] = 0.0f;
178 | m[ 2] = 0.0f;
179 | m[ 3] = 0.0f;
180 |
181 | m[ 4] = 0.0f;
182 | m[ 5] = 2.0f / height;
183 | m[ 6] = 0.0f;
184 | m[ 7] = 0.0f;
185 |
186 | m[ 8] = 0.0f;
187 | m[ 9] = 0.0f;
188 | m[10] = 1.0f/(farPlane - nearPlane);
189 | m[11] = 0.0f;
190 |
191 | m[12] = 0.0f;
192 | m[13] = 0.0f;
193 | m[14] = -nearPlane/(farPlane - nearPlane);
194 | m[15] = 1.0f;
195 | }
196 |
197 |
--------------------------------------------------------------------------------
/src/rasterizer/matrix4.h:
--------------------------------------------------------------------------------
1 | /*
2 | * matrix4.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_MATRIX4_H
9 | #define PR_MATRIX4_H
10 |
11 |
12 | #include "types.h"
13 | #include "vector3.h"
14 | #include "vector4.h"
15 |
16 |
17 | typedef struct pr_matrix4
18 | {
19 | // column (c) and row (r)
20 | // c r
21 | PRfloat m[4][4];
22 | }
23 | pr_matrix4;
24 |
25 |
26 | void _pr_matrix_load_identity(pr_matrix4* matrix);
27 | void _pr_matrix_copy(pr_matrix4* dst, const pr_matrix4* src);
28 |
29 | void _pr_matrix_mul_float3(PRfloat* result, const pr_matrix4* lhs, const PRfloat* rhs);
30 | void _pr_matrix_mul_float4(PRfloat* result, const pr_matrix4* lhs, const PRfloat* rhs);
31 |
32 | void _pr_matrix_mul_vector3(pr_vector3* result, const pr_matrix4* lhs, const pr_vector3* rhs);
33 | void _pr_matrix_mul_vector4(pr_vector4* result, const pr_matrix4* lhs, const pr_vector4* rhs);
34 |
35 | void _pr_matrix_mul_matrix(pr_matrix4* result, const pr_matrix4* lhs, const pr_matrix4* rhs);
36 |
37 | void _pr_matrix_translate(pr_matrix4* result, PRfloat x, PRfloat y, PRfloat z);
38 | void _pr_matrix_rotate(pr_matrix4* result, PRfloat x, PRfloat y, PRfloat z, PRfloat angle);
39 | void _pr_matrix_scale(pr_matrix4* result, PRfloat x, PRfloat y, PRfloat z);
40 |
41 | void _pr_matrix_build_perspective(pr_matrix4* result, PRfloat aspectRatio, PRfloat nearPlane, PRfloat farPlane, PRfloat fov);
42 | void _pr_matrix_build_orthogonal(pr_matrix4* result, PRfloat width, PRfloat height, PRfloat nearPlane, PRfloat farPlane);
43 |
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/src/rasterizer/pixel.h:
--------------------------------------------------------------------------------
1 | /*
2 | * pixel.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_PIXEL_H
9 | #define PR_PIXEL_H
10 |
11 |
12 | #include "types.h"
13 | #include "static_config.h"
14 | #include "color.h"
15 |
16 | #include
17 |
18 |
19 | #ifdef PR_DEPTH_BUFFER_8BIT
20 | #define PR_DEPTH_MAX UCHAR_MAX
21 | typedef PRubyte PRdepthtype;
22 | #else
23 | #define PR_DEPTH_MAX USHRT_MAX
24 | typedef PRushort PRdepthtype;
25 | #endif
26 |
27 | //! Frame buffer pixel structure.
28 | typedef struct pr_pixel
29 | {
30 | PRcolorindex colorIndex; //!< Colors are stored as 8-bit unsigned integer.
31 | PRdepthtype depth; //!< Depth values are stored as 16-bit unsigned integer.
32 | }
33 | pr_pixel;
34 |
35 |
36 | /**
37 | Writes the specified real depth value to a pixel depth.
38 | \param[in] z Specifies the real z value. This must be in the range [0.0 .. 1.0].
39 | */
40 | PR_INLINE PRdepthtype _pr_pixel_write_depth(PRinterp z)
41 | {
42 | return (PRdepthtype)(z * (PRinterp)PR_DEPTH_MAX);
43 | }
44 |
45 | //! Reads the specified pixel depth to a real depth value.
46 | PR_INLINE PRinterp _pr_pixel_read_depth(PRdepthtype z)
47 | {
48 | return ((PRinterp)z) / ((PRdepthtype)PR_DEPTH_MAX);
49 | }
50 |
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/src/rasterizer/raster_triangle.h:
--------------------------------------------------------------------------------
1 | /*
2 | * raster_triangle.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_RASTER_TRIANGLE_H
9 | #define PR_RASTER_TRIANGLE_H
10 |
11 |
12 | #include "raster_vertex.h"
13 |
14 |
15 | //!REMOVE THIS!
16 | typedef struct pr_raster_triangle
17 | {
18 | pr_raster_vertex a;
19 | pr_raster_vertex b;
20 | pr_raster_vertex c;
21 | }
22 | pr_raster_triangle;
23 |
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/src/rasterizer/raster_vertex.h:
--------------------------------------------------------------------------------
1 | /*
2 | * raster_vertex.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_RASTER_VERTEX_H
9 | #define PR_RASTER_VERTEX_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | //! Raster vertex structure before projection (for clipping)
16 | typedef struct pr_clip_vertex
17 | {
18 | PRfloat x; //!< X coordinate (in view space).
19 | PRfloat y; //!< Y coordinate (in view space).
20 | PRfloat z; //!< Z coordinate (in view space).
21 | PRfloat w; //!< W coordinate (in view space).
22 | PRfloat u; //!< Texture coordinate U.
23 | PRfloat v; //!< Texture coordinate V.
24 | }
25 | pr_clip_vertex;
26 |
27 | //! Raster vertex structure after projection
28 | typedef struct pr_raster_vertex
29 | {
30 | PRint x; //!< Screen coordinate X.
31 | PRint y; //!< Screen coordinate Y.
32 | PRinterp z; //!< Normalized device coordinate Z.
33 | PRinterp u; //!< Inverse texture coordinate U.
34 | PRinterp v; //!< Inverse texture coordinate V.
35 | }
36 | pr_raster_vertex;
37 |
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/src/rasterizer/rect.c:
--------------------------------------------------------------------------------
1 | /*
2 | * rect.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "rect.h"
9 |
10 |
11 | void _pr_rect_init(pr_rect* rect)
12 | {
13 | if (rect != NULL)
14 | {
15 | rect->left = 0;
16 | rect->top = 0;
17 | rect->right = 0;
18 | rect->bottom = 0;
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/src/rasterizer/rect.h:
--------------------------------------------------------------------------------
1 | /*
2 | * rect.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_RECT_H
9 | #define PR_RECT_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | typedef struct pr_rect
16 | {
17 | PRint left;
18 | PRint top;
19 | PRint right;
20 | PRint bottom;
21 | }
22 | pr_rect;
23 |
24 |
25 | void _pr_rect_init(pr_rect* rect);
26 |
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/src/rasterizer/render.h:
--------------------------------------------------------------------------------
1 | /*
2 | * render.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_RENDER_H
9 | #define PR_RENDER_H
10 |
11 |
12 | #include "types.h"
13 | #include "vertexbuffer.h"
14 | #include "indexbuffer.h"
15 |
16 |
17 | // --- points --- //
18 |
19 | void _pr_render_screenspace_point(PRint x, PRint y);
20 |
21 | void _pr_render_points(PRsizei numVertices, PRsizei firstVertex, /*const */pr_vertexbuffer* vertexBuffer);
22 |
23 | void _pr_render_indexed_points(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer, const pr_indexbuffer* indexBuffer);
24 |
25 | // --- lines --- //
26 |
27 | void _pr_render_screenspace_line(PRint x1, PRint y1, PRint x2, PRint y2);
28 |
29 | void _pr_render_lines(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer);
30 | void _pr_render_line_strip(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer);
31 | void _pr_render_line_loop(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer);
32 |
33 | void _pr_render_indexed_lines(PRsizei numVertices, PRsizei firstVertex, /*const */pr_vertexbuffer* vertexBuffer, const pr_indexbuffer* indexBuffer);
34 | void _pr_render_indexed_line_strip(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer, const pr_indexbuffer* indexBuffer);
35 | void _pr_render_indexed_line_loop(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer, const pr_indexbuffer* indexBuffer);
36 |
37 | // --- images --- //
38 |
39 | void _pr_render_screenspace_image(PRint left, PRint top, PRint right, PRint bottom);
40 |
41 | // --- triangles --- //
42 |
43 | void _pr_render_triangles(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer);
44 | void _pr_render_triangle_strip(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer);
45 | void _pr_render_triangle_fan(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer);
46 |
47 | void _pr_render_indexed_triangles(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer, const pr_indexbuffer* indexBuffer);
48 | void _pr_render_indexed_triangle_strip(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer, const pr_indexbuffer* indexBuffer);
49 | void _pr_render_indexed_triangle_fan(PRsizei numVertices, PRsizei firstVertex, const pr_vertexbuffer* vertexBuffer, const pr_indexbuffer* indexBuffer);
50 |
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/src/rasterizer/state_machine.c:
--------------------------------------------------------------------------------
1 | /*
2 | * state_machine.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "state_machine.h"
9 | #include "static_config.h"
10 | #include "error.h"
11 | #include "ext_math.h"
12 | #include "color_palette.h"
13 |
14 |
15 | static pr_state_machine _nullStateMachine;
16 | pr_state_machine* _stateMachine = &_nullStateMachine;
17 |
18 |
19 | static void _state_machine_cliprect(PRint left, PRint top, PRint right, PRint bottom)
20 | {
21 | _stateMachine->clipRect.left = left;
22 | _stateMachine->clipRect.right = right;
23 |
24 | #ifdef PR_ORIGIN_LEFT_TOP
25 |
26 | if (PR_STATE_MACHINE.boundFrameBuffer != NULL)
27 | {
28 | PRint height = (PRint)(PR_STATE_MACHINE.boundFrameBuffer->height);
29 | _stateMachine->clipRect.top = height - bottom - 1;
30 | _stateMachine->clipRect.bottom = height - top - 1;
31 | }
32 | else
33 | {
34 | _stateMachine->clipRect.top = top;
35 | _stateMachine->clipRect.bottom = bottom;
36 | }
37 |
38 | #else
39 |
40 | _stateMachine->clipRect.top = top;
41 | _stateMachine->clipRect.bottom = bottom;
42 |
43 | #endif
44 | }
45 |
46 | static void _update_cliprect()
47 | {
48 | // Get dimensions from viewport
49 | PRint left = PR_STATE_MACHINE.viewportRect.left;
50 | PRint top = PR_STATE_MACHINE.viewportRect.top;
51 | PRint right = PR_STATE_MACHINE.viewportRect.right;
52 | PRint bottom = PR_STATE_MACHINE.viewportRect.bottom;
53 |
54 | if (PR_STATE_MACHINE.states[PR_SCISSOR] != PR_FALSE)
55 | {
56 | // Get dimensions from scissor
57 | PR_CLAMP_LARGEST(left, PR_STATE_MACHINE.scissorRect.left);
58 | PR_CLAMP_LARGEST(top, PR_STATE_MACHINE.scissorRect.top);
59 | PR_CLAMP_SMALLEST(right, PR_STATE_MACHINE.scissorRect.right);
60 | PR_CLAMP_SMALLEST(bottom, PR_STATE_MACHINE.scissorRect.bottom);
61 | }
62 |
63 | // Clamp clipping rectangle
64 | const PRint maxWidth = PR_STATE_MACHINE.boundFrameBuffer->width - 1;
65 | const PRint maxHeight = PR_STATE_MACHINE.boundFrameBuffer->height - 1;
66 |
67 | _state_machine_cliprect(
68 | PR_CLAMP(left, 0, maxWidth),
69 | PR_CLAMP(top, 0, maxHeight),
70 | PR_CLAMP(right, 0, maxWidth),
71 | PR_CLAMP(bottom, 0, maxHeight)
72 | );
73 | }
74 |
75 | void _pr_ref_add(PRobject obj)
76 | {
77 | if (obj != NULL)
78 | ++_stateMachine->refCounter;
79 | }
80 |
81 | void _pr_ref_release(PRobject obj)
82 | {
83 | if (obj != NULL)
84 | {
85 | if (_stateMachine->refCounter == 0)
86 | _pr_error_set(PR_ERROR_INVALID_STATE, "object ref-counter underflow");
87 | else
88 | --_stateMachine->refCounter;
89 | }
90 | }
91 |
92 | void _pr_ref_assert(pr_state_machine* stateMachine)
93 | {
94 | if (stateMachine != NULL && stateMachine->refCounter != 0)
95 | {
96 | char msg[64];
97 | sprintf(msg, "object ref-counter is none zero ( %i )", stateMachine->refCounter);
98 | _pr_error_set(PR_ERROR_INVALID_STATE, msg);
99 | }
100 | }
101 |
102 | void _pr_state_machine_init(pr_state_machine* stateMachine)
103 | {
104 | _pr_matrix_load_identity(&(stateMachine->projectionMatrix));
105 | _pr_matrix_load_identity(&(stateMachine->viewMatrix));
106 | _pr_matrix_load_identity(&(stateMachine->worldMatrix));
107 | _pr_matrix_load_identity(&(stateMachine->worldViewMatrix));
108 | _pr_matrix_load_identity(&(stateMachine->worldViewProjectionMatrix));
109 |
110 | _pr_viewport_init(&(stateMachine->viewport));
111 |
112 | _pr_rect_init(&(stateMachine-> viewportRect));
113 | _pr_rect_init(&(stateMachine->scissorRect));
114 | _pr_rect_init(&(stateMachine->clipRect));
115 |
116 | stateMachine->boundFrameBuffer = NULL;
117 | stateMachine->boundVertexBuffer = NULL;
118 | stateMachine->boundIndexBuffer = NULL;
119 | stateMachine->boundTexture = NULL;
120 |
121 | stateMachine->clearColor = _pr_color_to_colorindex(0, 0, 0);
122 | stateMachine->color0 = _pr_color_to_colorindex(0, 0, 0);
123 | stateMachine->textureLodBias = 0;
124 | stateMachine->cullMode = PR_CULL_NONE;
125 | stateMachine->polygonMode = PR_POLYGON_FILL;
126 |
127 | stateMachine->states[PR_SCISSOR] = PR_FALSE;
128 | stateMachine->states[PR_MIP_MAPPING] = PR_FALSE;
129 |
130 | stateMachine->refCounter = 0;
131 | }
132 |
133 | void _pr_state_machine_init_null()
134 | {
135 | _pr_state_machine_init(&_nullStateMachine);
136 | }
137 |
138 | void _pr_state_machine_makecurrent(pr_state_machine* stateMachine)
139 | {
140 | if (stateMachine != NULL)
141 | _stateMachine = stateMachine;
142 | else
143 | _stateMachine = &_nullStateMachine;
144 | }
145 |
146 | void _pr_state_machine_set_state(PRenum cap, PRboolean state)
147 | {
148 | if (cap >= PR_NUM_STATES)
149 | {
150 | PR_ERROR(PR_ERROR_INDEX_OUT_OF_BOUNDS);
151 | return;
152 | }
153 |
154 | // Store new state
155 | PR_STATE_MACHINE.states[cap] = (state != PR_FALSE ? PR_TRUE : PR_FALSE);
156 |
157 | // Check for special cases (update functions)
158 | switch (cap)
159 | {
160 | case PR_SCISSOR:
161 | _update_cliprect();
162 | break;
163 | }
164 | }
165 |
166 | PRboolean _pr_state_machine_get_state(PRenum cap)
167 | {
168 | if (cap >= PR_NUM_STATES)
169 | {
170 | PR_ERROR(PR_ERROR_INDEX_OUT_OF_BOUNDS);
171 | return PR_FALSE;
172 | }
173 | return PR_STATE_MACHINE.states[cap];
174 | }
175 |
176 | void _pr_state_machine_set_texenvi(PRenum param, PRint value)
177 | {
178 | switch (param)
179 | {
180 | case PR_TEXTURE_LOD_BIAS:
181 | PR_STATE_MACHINE.textureLodBias = (PRubyte)PR_CLAMP(value, 0, 255);
182 | break;
183 | default:
184 | PR_ERROR(PR_ERROR_INDEX_OUT_OF_BOUNDS);
185 | break;
186 | }
187 | }
188 |
189 | PRint _pr_state_machine_get_texenvi(PRenum param)
190 | {
191 | switch (param)
192 | {
193 | case PR_TEXTURE_LOD_BIAS:
194 | return (PRint)PR_STATE_MACHINE.textureLodBias;
195 | default:
196 | PR_ERROR(PR_ERROR_INDEX_OUT_OF_BOUNDS);
197 | return 0;
198 | }
199 | }
200 |
201 | void _pr_state_machine_bind_framebuffer(pr_framebuffer* frameBuffer)
202 | {
203 | PR_STATE_MACHINE.boundFrameBuffer = frameBuffer;
204 | if (frameBuffer != NULL)
205 | _state_machine_cliprect(0, 0, (PRint)frameBuffer->width - 1, (PRint)frameBuffer->height - 1);
206 | else
207 | _state_machine_cliprect(0, 0, 0, 0);
208 | }
209 |
210 | void _pr_state_machine_bind_vertexbuffer(pr_vertexbuffer* vertexBuffer)
211 | {
212 | PR_STATE_MACHINE.boundVertexBuffer = vertexBuffer;
213 | }
214 |
215 | void _pr_state_machine_bind_indexbuffer(pr_indexbuffer* indexBuffer)
216 | {
217 | PR_STATE_MACHINE.boundIndexBuffer = indexBuffer;
218 | }
219 |
220 | void _pr_state_machine_bind_texture(pr_texture* texture)
221 | {
222 | PR_STATE_MACHINE.boundTexture = texture;
223 | }
224 |
225 | void _pr_state_machine_viewport(PRint x, PRint y, PRint width, PRint height)
226 | {
227 | if (PR_STATE_MACHINE.boundFrameBuffer == NULL)
228 | {
229 | PR_ERROR(PR_ERROR_INVALID_STATE);
230 | return;
231 | }
232 |
233 | /*
234 | Store width and height with half size, to avoid this multiplication
235 | while transforming the normalized device coordinates (NDC) into viewspace.
236 | */
237 | PR_STATE_MACHINE.viewport.x = (PRfloat)x;
238 |
239 | #ifdef PR_ORIGIN_LEFT_TOP
240 | PR_STATE_MACHINE.viewport.y = (PRfloat)(PR_STATE_MACHINE.boundFrameBuffer->height - 1 - y);
241 | #else
242 | PR_STATE_MACHINE.viewport.y = (PRfloat)y;
243 | #endif
244 |
245 | PR_STATE_MACHINE.viewport.halfWidth = 0.5f * (PRfloat)width;
246 | PR_STATE_MACHINE.viewport.halfHeight = -0.5f * (PRfloat)height;
247 |
248 | // Store viewport rectangle
249 | PR_STATE_MACHINE.viewportRect.left = x;
250 | PR_STATE_MACHINE.viewportRect.top = y;
251 | PR_STATE_MACHINE.viewportRect.right = x + width;
252 | PR_STATE_MACHINE.viewportRect.bottom = y + height;
253 |
254 | // Update clipping rectangle
255 | _update_cliprect();
256 | }
257 |
258 | void _pr_state_machine_depth_range(PRfloat minDepth, PRfloat maxDepth)
259 | {
260 | PR_STATE_MACHINE.viewport.minDepth = minDepth;
261 | PR_STATE_MACHINE.viewport.maxDepth = maxDepth;
262 | PR_STATE_MACHINE.viewport.depthSize = maxDepth - minDepth;
263 | }
264 |
265 | void _pr_state_machine_scissor(PRint x, PRint y, PRint width, PRint height)
266 | {
267 | // Store scissor rectangle
268 | PR_STATE_MACHINE.scissorRect.left = x;
269 | PR_STATE_MACHINE.scissorRect.top = y;
270 | PR_STATE_MACHINE.scissorRect.right = x + width;
271 | PR_STATE_MACHINE.scissorRect.bottom = y + height;
272 |
273 | if (PR_STATE_MACHINE.states[PR_SCISSOR] != PR_FALSE)
274 | {
275 | // Update clipping rectangle
276 | _update_cliprect();
277 | }
278 | }
279 |
280 | void _pr_state_machine_cull_mode(PRenum mode)
281 | {
282 | if (mode < PR_CULL_NONE || mode > PR_CULL_BACK)
283 | PR_ERROR(PR_ERROR_INVALID_ARGUMENT);
284 | else
285 | PR_STATE_MACHINE.cullMode = mode;
286 | }
287 |
288 | void _pr_state_machine_polygon_mode(PRenum mode)
289 | {
290 | if (mode < PR_POLYGON_FILL || mode > PR_POLYGON_POINT)
291 | PR_ERROR(PR_ERROR_INVALID_ARGUMENT);
292 | else
293 | PR_STATE_MACHINE.polygonMode = mode;
294 | }
295 |
296 | static void _update_viewprojection_matrix()
297 | {
298 | _pr_matrix_mul_matrix(
299 | &(PR_STATE_MACHINE.viewProjectionMatrix),
300 | &(PR_STATE_MACHINE.projectionMatrix),
301 | &(PR_STATE_MACHINE.viewMatrix)
302 | );
303 | }
304 |
305 | static void _update_worldview_matrix()
306 | {
307 | _pr_matrix_mul_matrix(
308 | &(PR_STATE_MACHINE.worldViewMatrix),
309 | &(PR_STATE_MACHINE.viewMatrix),
310 | &(PR_STATE_MACHINE.worldMatrix)
311 | );
312 | }
313 |
314 | static void _update_worldviewprojection_matrix()
315 | {
316 | _pr_matrix_mul_matrix(
317 | &(PR_STATE_MACHINE.worldViewProjectionMatrix),
318 | &(PR_STATE_MACHINE.viewProjectionMatrix),
319 | &(PR_STATE_MACHINE.worldMatrix)
320 | );
321 | }
322 |
323 | void _pr_state_machine_projection_matrix(const pr_matrix4* matrix)
324 | {
325 | _pr_matrix_copy(&(PR_STATE_MACHINE.projectionMatrix), matrix);
326 | _update_viewprojection_matrix();
327 | _update_worldviewprojection_matrix();
328 | }
329 |
330 | void _pr_state_machine_view_matrix(const pr_matrix4* matrix)
331 | {
332 | _pr_matrix_copy(&(PR_STATE_MACHINE.viewMatrix), matrix);
333 | _update_viewprojection_matrix();
334 | _update_worldview_matrix();
335 | _update_worldviewprojection_matrix();
336 | }
337 |
338 | void _pr_state_machine_world_matrix(const pr_matrix4* matrix)
339 | {
340 | _pr_matrix_copy(&(PR_STATE_MACHINE.worldMatrix), matrix);
341 | _update_worldview_matrix();
342 | _update_worldviewprojection_matrix();
343 | }
344 |
345 |
--------------------------------------------------------------------------------
/src/rasterizer/state_machine.h:
--------------------------------------------------------------------------------
1 | /*
2 | * state_machine.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_STATE_MACHINE_H
9 | #define PR_STATE_MACHINE_H
10 |
11 |
12 | #include "matrix4.h"
13 | #include "viewport.h"
14 | #include "rect.h"
15 | #include "framebuffer.h"
16 | #include "vertexbuffer.h"
17 | #include "indexbuffer.h"
18 | #include "texture.h"
19 | #include "enums.h"
20 |
21 |
22 | #define PR_STATE_MACHINE (*_stateMachine)
23 | #define PR_NUM_STATES 2
24 |
25 |
26 | typedef struct pr_state_machine
27 | {
28 | pr_matrix4 projectionMatrix;
29 | pr_matrix4 viewMatrix;
30 | pr_matrix4 worldMatrix;
31 | pr_matrix4 viewProjectionMatrix;
32 | pr_matrix4 worldViewMatrix;
33 | pr_matrix4 worldViewProjectionMatrix;
34 |
35 | pr_viewport viewport;
36 |
37 | pr_rect viewportRect;
38 | pr_rect scissorRect;
39 | pr_rect clipRect;
40 |
41 | pr_framebuffer* boundFrameBuffer;
42 | pr_vertexbuffer* boundVertexBuffer;
43 | pr_indexbuffer* boundIndexBuffer;
44 | pr_texture* boundTexture;
45 |
46 | PRcolorindex clearColor;
47 | PRcolorindex color0; // Active color index
48 | PRubyte textureLodBias;
49 |
50 | PRenum cullMode;
51 | PRenum polygonMode;
52 |
53 | PRboolean states[PR_NUM_STATES];
54 |
55 | PRsizei refCounter; // Object reference counter
56 | }
57 | pr_state_machine;
58 |
59 |
60 | //! Reference to the state machine of the current context.
61 | extern pr_state_machine* _stateMachine;
62 |
63 |
64 | void _pr_ref_add(PRobject obj);
65 | void _pr_ref_release(PRobject obj);
66 | void _pr_ref_assert(pr_state_machine* stateMachine);
67 |
68 | void _pr_state_machine_init(pr_state_machine* stateMachine);
69 | void _pr_state_machine_init_null();
70 |
71 | void _pr_state_machine_makecurrent(pr_state_machine* stateMachine);
72 |
73 | void _pr_state_machine_set_state(PRenum cap, PRboolean state);
74 | PRboolean _pr_state_machine_get_state(PRenum cap);
75 |
76 | void _pr_state_machine_set_texenvi(PRenum param, PRint value);
77 | PRint _pr_state_machine_get_texenvi(PRenum param);
78 |
79 | void _pr_state_machine_bind_framebuffer(pr_framebuffer* frameBuffer);
80 | void _pr_state_machine_bind_vertexbuffer(pr_vertexbuffer* vertexBuffer);
81 | void _pr_state_machine_bind_indexbuffer(pr_indexbuffer* indexBuffer);
82 | void _pr_state_machine_bind_texture(pr_texture* texture);
83 |
84 | void _pr_state_machine_viewport(PRint x, PRint y, PRint width, PRint height);
85 | void _pr_state_machine_depth_range(PRfloat minDepth, PRfloat maxDepth);
86 | void _pr_state_machine_scissor(PRint x, PRint y, PRint width, PRint height);
87 | void _pr_state_machine_cull_mode(PRenum mode);
88 | void _pr_state_machine_polygon_mode(PRenum mode);
89 |
90 | void _pr_state_machine_projection_matrix(const pr_matrix4* matrix);
91 | void _pr_state_machine_view_matrix(const pr_matrix4* matrix);
92 | void _pr_state_machine_world_matrix(const pr_matrix4* matrix);
93 |
94 |
95 | #endif
96 |
--------------------------------------------------------------------------------
/src/rasterizer/static_config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * static_config.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_STATIC_CONFIG_H
9 | #define PR_STATIC_CONFIG_H
10 |
11 |
12 | // Version number
13 | #define PR_VERSION_MAJOR 0
14 | #define PR_VERSION_MINOR 1
15 | #define PR_VERSION_REVISION 0
16 | #define PR_VERSION_STATUS "alpha"
17 | #define PR_VERSION_STR "0.1 alpha"
18 |
19 | //! Use BGR color output instead of RGB (used for Win32 GDI)
20 | #ifdef _WIN32
21 | # define PR_BGR_COLOR_OUTPUT
22 | #endif
23 |
24 | //! Includes the STB image file handler plugin
25 | #define PR_INCLUDE_PLUGINS
26 |
27 | //! Flips the screen space vertical
28 | #define PR_ORIGIN_LEFT_TOP
29 |
30 | //! Makes excessive use of the approximated math functions
31 | #define PR_FAST_MATH
32 |
33 | //! Enables extended debug information
34 | #define PR_DEBUG
35 |
36 | //! Use perspective corrected depth and texture coordinates
37 | #define PR_PERSPECTIVE_CORRECTED
38 |
39 | //! Use an 8-bit depth buffer (instead of 16 bit)
40 | //#define PR_DEPTH_BUFFER_8BIT
41 |
42 | //! Use a 64-bit interpolation type instead of 32-bit
43 | #define PR_INTERP_64BIT
44 |
45 | //! Use a 24-bit color buffer (instead of 8 bit)
46 | //#define PR_COLOR_BUFFER_24BIT
47 |
48 | //! Merge color- and depth buffers to a single one inside a frame buffer.
49 | #define PR_MERGE_COLOR_AND_DEPTH_BUFFERS //!CAN NOT BE DISABLED YET!
50 |
51 | //! Makes all pixels with color black a transparent pixel.
52 | #define PR_BLACK_IS_ALPHA
53 |
54 |
55 | #ifdef PR_INTERP_64BIT
56 | //! 64-bit interpolation type.
57 | typedef double PRinterp;
58 | #define PR_FLOAT(x) x
59 | #else
60 | //! 32-bit interpolation type.
61 | typedef float PRinterp;
62 | #define PR_FLOAT(x) x##f
63 | #endif
64 |
65 |
66 | #endif
67 |
--------------------------------------------------------------------------------
/src/rasterizer/texture.c:
--------------------------------------------------------------------------------
1 | /*
2 | * texture.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "texture.h"
9 | #include "ext_math.h"
10 | #include "error.h"
11 | #include "helper.h"
12 | #include "image.h"
13 | #include "state_machine.h"
14 | #include "enums.h"
15 |
16 | #include
17 | #include
18 | #include
19 |
20 |
21 | // --- internals --- //
22 |
23 | static void _texture_subimage2d(
24 | PRcolorindex* texels, PRubyte mip, PRtexsize width, PRtexsize height, PRenum format, const PRvoid* data, PRboolean dither)
25 | {
26 | if (format != PR_UBYTE_RGB)
27 | {
28 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
29 | return;
30 | }
31 |
32 | // Setup structure for sub-image
33 | pr_image subimage;
34 | subimage.width = width;
35 | subimage.height = height;
36 | subimage.format = 3;
37 | subimage.defFree = PR_TRUE;
38 | subimage.colors = (PRubyte*)data;
39 |
40 | _pr_image_color_to_colorindex(texels, &subimage, dither);
41 | }
42 |
43 | static void _texture_subimage2d_rect(
44 | pr_texture* texture, PRubyte mip, PRtexsize x, PRtexsize y, PRtexsize width, PRtexsize height, PRenum format, const PRvoid* data)
45 | {
46 | //...
47 | }
48 |
49 | static PRubyte _color_box4_blur(PRubyte a, PRubyte b, PRubyte c, PRubyte d)
50 | {
51 | PRint x;
52 | x = a;
53 | x += b;
54 | x += c;
55 | x += d;
56 | return (PRubyte)(x / 4);
57 | }
58 |
59 | static PRubyte _color_box2_blur(PRubyte a, PRubyte b)
60 | {
61 | PRint x;
62 | x = a;
63 | x += b;
64 | return (PRubyte)(x / 2);
65 | }
66 |
67 | static PRubyte* _image_scale_down_ubyte_rgb(PRtexsize width, PRtexsize height, const PRubyte* data)
68 | {
69 | #define COLOR(x, y, i) data[((y)*width + (x))*3 + (i)]
70 |
71 | const PRtexsize scaledWidth = (width > 1 ? width/2 : 1);
72 | const PRtexsize scaledHeight = (height > 1 ? height/2 : 1);
73 |
74 | PRubyte* scaled = PR_CALLOC(PRubyte, scaledWidth*scaledHeight*3);
75 |
76 | if (width > 1 && height > 1)
77 | {
78 | for (PRtexsize y = 0; y < scaledHeight; ++y)
79 | {
80 | for (PRtexsize x = 0; x < scaledWidth; ++x)
81 | {
82 | for (PRint i = 0; i < 3; ++i)
83 | {
84 | scaled[(y*scaledWidth + x)*3 + i] = _color_box4_blur(
85 | COLOR(x*2 , y*2 , i),
86 | COLOR(x*2 + 1, y*2 , i),
87 | COLOR(x*2 + 1, y*2 + 1, i),
88 | COLOR(x*2 , y*2 + 1, i)
89 | );
90 | }
91 | }
92 | }
93 | }
94 | else if (width > 1)
95 | {
96 | for (PRtexsize x = 0; x < scaledWidth; ++x)
97 | {
98 | for (PRint i = 0; i < 3; ++i)
99 | {
100 | scaled[x*3 + i] = _color_box2_blur(
101 | COLOR(x*2 , 0, i),
102 | COLOR(x*2 + 1, 0, i)
103 | );
104 | }
105 | }
106 | }
107 | else if (height > 1)
108 | {
109 | for (PRtexsize y = 0; y < scaledHeight; ++y)
110 | {
111 | for (PRint i = 0; i < 3; ++i)
112 | {
113 | scaled[y*scaledWidth*3 + i] = _color_box2_blur(
114 | COLOR(0, y*2 , i),
115 | COLOR(0, y*2 + 1, i)
116 | );
117 | }
118 | }
119 | }
120 |
121 | return scaled;
122 |
123 | #undef COLOR
124 | }
125 |
126 | static PRubyte* _image_scale_down(PRtexsize width, PRtexsize height, PRenum format, const PRvoid* data)
127 | {
128 | switch (format)
129 | {
130 | case PR_UBYTE_RGB:
131 | return _image_scale_down_ubyte_rgb(width, height, (const PRubyte*)data);
132 | default:
133 | break;
134 | }
135 | return NULL;
136 | }
137 |
138 | // --- interface --- //
139 |
140 | pr_texture* _pr_texture_create()
141 | {
142 | // Create texture
143 | pr_texture* texture = PR_MALLOC(pr_texture);
144 |
145 | texture->width = 0;
146 | texture->height = 0;
147 | texture->mips = 0;
148 | texture->texels = NULL;
149 |
150 | for (size_t i = 0; i < PR_MAX_NUM_MIPS; ++i)
151 | texture->mipTexels[i] = NULL;
152 |
153 | _pr_ref_add(texture);
154 |
155 | return texture;
156 | }
157 |
158 | void _pr_texture_delete(pr_texture* texture)
159 | {
160 | if (texture != NULL)
161 | {
162 | _pr_ref_release(texture);
163 |
164 | PR_FREE(texture->texels);
165 | PR_FREE(texture);
166 | }
167 | }
168 |
169 | void _pr_texture_singular_init(pr_texture* texture)
170 | {
171 | if (texture != NULL)
172 | {
173 | texture->width = 1;
174 | texture->height = 1;
175 | texture->mips = 0;
176 | texture->texels = PR_CALLOC(PRcolorindex, 1);
177 | }
178 | }
179 |
180 | void _pr_texture_singular_clear(pr_texture* texture)
181 | {
182 | if (texture != NULL)
183 | PR_FREE(texture->texels);
184 | }
185 |
186 | PRboolean _pr_texture_image2d(
187 | pr_texture* texture, PRtexsize width, PRtexsize height, PRenum format, const PRvoid* data, PRboolean dither, PRboolean generateMips)
188 | {
189 | // Validate parameters
190 | if (texture == NULL)
191 | {
192 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
193 | return PR_FALSE;
194 | }
195 | if (width == 0 || height == 0)
196 | {
197 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, "textures must not have a size equal to zero");
198 | return PR_FALSE;
199 | }
200 | if (width > PR_MAX_TEX_SIZE || height > PR_MAX_TEX_SIZE)
201 | {
202 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, "maximum texture size exceeded");
203 | return PR_FALSE;
204 | }
205 |
206 | // Determine number of texels
207 | PRubyte mips = 0;
208 | size_t numTexels = 0;
209 |
210 | if (generateMips != PR_FALSE)
211 | {
212 | PRtexsize w = width;
213 | PRtexsize h = height;
214 |
215 | while (1)
216 | {
217 | // Count number of texels
218 | numTexels += w*h;
219 | ++mips;
220 |
221 | if (w == 1 && h == 1)
222 | break;
223 |
224 | // Halve MIP size
225 | if (w > 1)
226 | w /= 2;
227 | if (h > 1)
228 | h /= 2;
229 | }
230 | }
231 | else
232 | {
233 | mips = 1;
234 | numTexels = width*height;
235 | }
236 |
237 | // Check if texels must be reallocated
238 | if (texture->width != width || texture->height != height || texture->mips != mips)
239 | {
240 | // Setup new texture dimension
241 | texture->width = width;
242 | texture->height = height;
243 | texture->mips = mips;
244 |
245 | // Free previous texels
246 | PR_FREE(texture->texels);
247 |
248 | // Create texels
249 | texture->texels = PR_CALLOC(PRcolorindex, numTexels);
250 |
251 | // Setup MIP texel offsets
252 | const PRcolorindex* texels = texture->texels;
253 | PRtexsize w = width, h = height;
254 |
255 | for (PRubyte mip = 0; mip < texture->mips; ++mip)
256 | {
257 | // Store current texel offset
258 | texture->mipTexels[mip] = texels;
259 |
260 | // Goto next texel MIP level
261 | texels += w*h;
262 |
263 | // Halve MIP size
264 | if (w > 1)
265 | w /= 2;
266 | if (h > 1)
267 | h /= 2;
268 | }
269 | }
270 |
271 | // Fill image data of first MIP level
272 | PRcolorindex* texels = texture->texels;
273 |
274 | _texture_subimage2d(texels, 0, width, height, format, data, dither);
275 |
276 | if (generateMips != PR_FALSE)
277 | {
278 | PRvoid* prevData = (PRvoid*)data;
279 |
280 | // Fill image data
281 | for (PRubyte mip = 1; mip < texture->mips; ++mip)
282 | {
283 | // Goto next texel MIP level
284 | texels += width*height;
285 |
286 | // Scale down image data
287 | data = _image_scale_down(width, height, format, prevData);
288 |
289 | if (mip > 1)
290 | PR_FREE(prevData);
291 | prevData = (PRvoid*)data;
292 |
293 | if (data == NULL)
294 | {
295 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
296 | return PR_FALSE;
297 | }
298 |
299 | // Halve MIP size
300 | if (width > 1)
301 | width /= 2;
302 | if (height > 1)
303 | height /= 2;
304 |
305 | // Fill image data for current MIP level
306 | _texture_subimage2d(texels, mip, width, height, format, data, dither);
307 | }
308 |
309 | PR_FREE(prevData);
310 | }
311 |
312 | return PR_TRUE;
313 | }
314 |
315 | PRboolean _pr_texture_subimage2d(
316 | pr_texture* texture, PRubyte mip, PRtexsize x, PRtexsize y, PRtexsize width, PRtexsize height, PRenum format, const PRvoid* data, PRboolean dither)
317 | {
318 | // Validate parameters
319 | if (texture == NULL)
320 | {
321 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
322 | return PR_FALSE;
323 | }
324 | if (texture->texels == NULL || x < 0 || y < 0 || x + width >= texture->width || y + height >= texture->height || width <= 0 || height <= 0 || mip >= texture->mips)
325 | {
326 | _pr_error_set(PR_ERROR_INVALID_ARGUMENT, __FUNCTION__);
327 | return PR_FALSE;
328 | }
329 |
330 | // Fill image data for specified MIP level
331 | _texture_subimage2d_rect(texture, mip, x, y, width, height, format, data);
332 |
333 | return PR_TRUE;
334 | }
335 |
336 | PRubyte _pr_texture_num_mips(PRubyte maxSize)
337 | {
338 | return maxSize > 0 ? (PRubyte)(floorf(log2f(maxSize))) + 1 : 0;
339 | }
340 |
341 | const PRcolorindex* _pr_texture_select_miplevel(const pr_texture* texture, PRubyte mip, PRtexsize* width, PRtexsize* height)
342 | {
343 | // Return texel buffer (MIP-map 0) if there are no MIP-maps
344 | if (texture->mips == 0)
345 | return texture->texels;
346 |
347 | // Add MIP level offset
348 | mip = PR_CLAMP((PRubyte)(((PRint)mip) + _stateMachine->textureLodBias), 0, texture->mips - 1);
349 |
350 | // Store mip size in output parameters
351 | *width = PR_MIP_SIZE(texture->width, mip);
352 | *height = PR_MIP_SIZE(texture->height, mip);
353 |
354 | // Return MIP-map texel offset
355 | return texture->mipTexels[mip];
356 | }
357 |
358 | /*PRubyte _pr_texture_compute_miplevel(const pr_texture* texture, PRfloat r1x, PRfloat r1y, PRfloat r2x, PRfloat r2y)
359 | {
360 | // Compute derivation of u and v vectors
361 | r1x = fabsf(r1x);// * texture->width;
362 | r1y = fabsf(r1y);// * texture->height;
363 |
364 | r2x = fabsf(r2x);// * texture->width;
365 | r2y = fabsf(r2y);// * texture->height;
366 |
367 | // Select LOD by maximal derivation vector length (using dot product)
368 | PRfloat r1_len = sqrtf(r1x*r1x + r1y*r1y);
369 | PRfloat r2_len = sqrtf(r2x*r2x + r2y*r2y);
370 | PRfloat d = PR_MAX(r1_len, r2_len)*10.0f;
371 |
372 | // Clamp LOD to [0, texture->texture->mips)
373 | PRint lod = _int_log2(d);
374 | //PRint lod = (PRint)log2f(d);
375 | return (PRubyte)PR_CLAMP(lod, 0, texture->mips - 1);
376 | }*/
377 |
378 | PRcolorindex _pr_texture_sample_nearest_from_mipmap(const PRcolorindex* mipTexels, PRtexsize mipWidth, PRtexsize mipHeight, PRfloat u, PRfloat v)
379 | {
380 | // Clamp texture coordinates
381 | PRint x = (PRint)((u - (PRint)u)*mipWidth);
382 | PRint y = (PRint)((v - (PRint)v)*mipHeight);
383 |
384 | if (x < 0)
385 | x += mipWidth;
386 | if (y < 0)
387 | y += mipHeight;
388 |
389 | // Sample from texels
390 | return mipTexels[y*mipWidth + x];
391 | }
392 |
393 | PRcolorindex _pr_texture_sample_nearest(const pr_texture* texture, PRfloat u, PRfloat v, PRfloat ddx, PRfloat ddy)
394 | {
395 | // Select MIP-level texels by tex-coord derivation
396 | const PRfloat dx = ddx * texture->width;
397 | const PRfloat dy = ddy * texture->height;
398 |
399 | const PRfloat deltaMaxSq = PR_MAX(dx*dx, dy*dy);
400 |
401 | const PRint lod = _int_log2(deltaMaxSq);// / 2;
402 | const PRubyte mip = (PRubyte)PR_CLAMP(lod, 0, texture->mips - 1);
403 |
404 | // Get texels from MIP-level
405 | PRtexsize w, h;
406 | const PRcolorindex* texels = _pr_texture_select_miplevel(texture, mip, &w, &h);
407 |
408 | // Sample nearest texel
409 | return _pr_texture_sample_nearest_from_mipmap(texels, w, h, u, v);
410 | //return _pr_color_to_colorindex_r3g3b2(mip*20, mip*20, mip*20);
411 | }
412 |
413 | PRint _pr_texture_get_mip_parameter(const pr_texture* texture, PRubyte mip, PRenum param)
414 | {
415 | if (texture == NULL || mip >= texture->mips || param < PR_TEXTURE_WIDTH || param > PR_TEXTURE_HEIGHT)
416 | {
417 | PR_ERROR(PR_ERROR_INVALID_ARGUMENT);
418 | return 0;
419 | }
420 |
421 | switch (param)
422 | {
423 | case PR_TEXTURE_WIDTH:
424 | return (texture->width << mip);
425 | case PR_TEXTURE_HEIGHT:
426 | return (texture->height << mip);
427 | }
428 |
429 | return 0;
430 | }
431 |
432 |
--------------------------------------------------------------------------------
/src/rasterizer/texture.h:
--------------------------------------------------------------------------------
1 | /*
2 | * texture.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_TEXTURE_H
9 | #define PR_TEXTURE_H
10 |
11 |
12 | #include "types.h"
13 | #include "enums.h"
14 | #include "vector2.h"
15 | #include "color.h"
16 |
17 |
18 | // Maximal 11 MIP-maps restricts the textures to have a
19 | // maximum size of (2^(11-1) = 1024) in width and height.
20 | #define PR_MAX_NUM_MIPS 11
21 | #define PR_MAX_TEX_SIZE 1024
22 |
23 | #define PR_MIP_SIZE(size, mip) ((size) >> (mip))
24 | #define PR_TEXTURE_HAS_MIPS(tex) ((tex)->mips > 1)
25 |
26 |
27 | //! Textures can have a maximum size of 256x256 texels.
28 | //! Textures store all their mip maps in a single texel array for compact memory access.
29 | typedef struct pr_texture
30 | {
31 | PRtexsize width; //!< Width of the first MIP level.
32 | PRtexsize height; //!< Height of the first MIP level.
33 | PRubyte mips; //!< Number of MIP levels.
34 | PRcolorindex* texels; //!< Texel MIP chain.
35 | const PRcolorindex* mipTexels[PR_MAX_NUM_MIPS]; //!< Texel offsets for the MIP chain (Use a static array for better cache locality).
36 | }
37 | pr_texture;
38 |
39 |
40 | pr_texture* _pr_texture_create();
41 | void _pr_texture_delete(pr_texture* texture);
42 |
43 | void _pr_texture_singular_init(pr_texture* texture);
44 | void _pr_texture_singular_clear(pr_texture* texture);
45 |
46 | //! Sets the single color to the specified texture. No null pointer assertion!
47 | PR_INLINE void _pr_texture_singular_color(pr_texture* texture, PRcolorindex colorIndex)
48 | {
49 | texture->texels[0] = colorIndex;
50 | }
51 |
52 | //! Sets the 2D image data to the specified texture.
53 | PRboolean _pr_texture_image2d(
54 | pr_texture* texture,
55 | PRtexsize width, PRtexsize height,
56 | PRenum format, const PRvoid* data, PRboolean dither, PRboolean generateMips
57 | );
58 |
59 | PRboolean _pr_texture_subimage2d(
60 | pr_texture* texture,
61 | PRubyte mip, PRtexsize x, PRtexsize y,
62 | PRtexsize width, PRtexsize height,
63 | PRenum format, const PRvoid* data, PRboolean dither
64 | );
65 |
66 | //! Returns the number of MIP levels for the specified maximal texture dimension (width or height).
67 | PRubyte _pr_texture_num_mips(PRubyte maxSize);
68 |
69 | //! Returns a pointer to the specified texture MIP level.
70 | const PRcolorindex* _pr_texture_select_miplevel(const pr_texture* texture, PRubyte mip, PRtexsize* width, PRtexsize* height);
71 |
72 | //! Returns the MIP level index for the specified texture.
73 | //PRubyte _pr_texture_compute_miplevel(const pr_texture* texture, PRfloat r1x, PRfloat r1y, PRfloat r2x, PRfloat r2y);
74 |
75 | //! Samples the nearest texel from the specified MIP-map level.
76 | PRcolorindex _pr_texture_sample_nearest_from_mipmap(const PRcolorindex* mipTexels, PRtexsize mipWidth, PRtexsize mipHeight, PRfloat u, PRfloat v);
77 |
78 | //! Samples the nearest texel from the specified texture. MIP-map selection is compuited by tex-coord derivations ddx and ddy.
79 | PRcolorindex _pr_texture_sample_nearest(const pr_texture* texture, PRfloat u, PRfloat v, PRfloat ddx, PRfloat ddy);
80 |
81 | //! Returns a parameter of the specified texture MIP-map level.
82 | PRint _pr_texture_get_mip_parameter(const pr_texture* texture, PRubyte mip, PRenum param);
83 |
84 |
85 | #endif
86 |
--------------------------------------------------------------------------------
/src/rasterizer/vector2.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vector2.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_VECTOR2_H
9 | #define PR_VECTOR2_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | typedef struct pr_vector2
16 | {
17 | PRfloat x;
18 | PRfloat y;
19 | }
20 | pr_vector2;
21 |
22 |
23 | PR_INLINE PRfloat _pr_vector2_dot(pr_vector2 a, pr_vector2 b)
24 | {
25 | return a.x*b.x + a.y*b.y;
26 | }
27 |
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/src/rasterizer/vector3.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vector3.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "vector3.h"
9 | #include "ext_math.h"
10 |
11 | #include
12 |
13 |
14 | void _pr_vector_normalize3(pr_vector3* vec)
15 | {
16 | PRfloat len = PR_SQ(vec->x) + PR_SQ(vec->y) + PR_SQ(vec->z);
17 | if (len != 0.0f && len != 1.0f)
18 | {
19 | len = PR_INV_SQRT(len);
20 | vec->x *= len;
21 | vec->y *= len;
22 | vec->z *= len;
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/src/rasterizer/vector3.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vector3.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_VECTOR3_H
9 | #define PR_VECTOR3_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | typedef struct pr_vector3
16 | {
17 | PRfloat x;
18 | PRfloat y;
19 | PRfloat z;
20 | }
21 | pr_vector3;
22 |
23 |
24 | void _pr_vector_normalize3(pr_vector3* vec);
25 |
26 | PR_INLINE PRfloat _pr_vector3_dot(pr_vector3 a, pr_vector3 b)
27 | {
28 | return a.x*b.x + a.y*b.y + a.z*b.z;
29 | }
30 |
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/src/rasterizer/vector4.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vector4.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_VECTOR4_H
9 | #define PR_VECTOR4_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | typedef struct pr_vector4
16 | {
17 | PRfloat x;
18 | PRfloat y;
19 | PRfloat z;
20 | PRfloat w;
21 | }
22 | pr_vector4;
23 |
24 |
25 | PR_INLINE PRfloat _pr_vector4_dot(pr_vector4 a, pr_vector4 b)
26 | {
27 | return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
28 | }
29 |
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/src/rasterizer/vector_arithmetic.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vector_arithmetic.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_VECTOR_ARITHMETIC_H
9 | #define PR_VECTOR_ARITHMETIC_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | void _pr_vector_normalize3(PRfloat* vec);
16 |
17 |
18 | #endif
19 |
--------------------------------------------------------------------------------
/src/rasterizer/vertex.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vertex.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "vertex.h"
9 |
10 | #include
11 |
12 |
13 | void _pr_vertex_init(pr_vertex* vertex)
14 | {
15 | if (vertex != NULL)
16 | memset(vertex, 0, sizeof(pr_vertex));
17 | }
18 |
--------------------------------------------------------------------------------
/src/rasterizer/vertex.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vertex.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_VERTEX_H
9 | #define PR_VERTEX_H
10 |
11 |
12 | #include "vector2.h"
13 | #include "vector3.h"
14 | #include "vector4.h"
15 | #include "matrix4.h"
16 | #include "static_config.h"
17 |
18 |
19 | //! Simple vertex with 3D coordinate and 2D texture-coordinate.
20 | typedef struct pr_vertex
21 | {
22 | // Before vertex processing
23 | pr_vector4 coord; //!< Original coordinate.
24 | pr_vector2 texCoord; //!< Texture-coordinate.
25 |
26 | #if 1//!remove!
27 | pr_vector4 ndc; //!< Normalized device coordinate.
28 | #ifdef PR_PERSPECTIVE_CORRECTED
29 | pr_vector2 invTexCoord; //!< Inverse texture-coordinates.
30 | #endif
31 | #endif
32 | }
33 | pr_vertex;
34 |
35 |
36 | void _pr_vertex_init(pr_vertex* vertex);
37 |
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/src/rasterizer/vertexbuffer.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vertexbuffer.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "vertexbuffer.h"
9 | #include "state_machine.h"
10 | #include "error.h"
11 | #include "helper.h"
12 | #include "static_config.h"
13 |
14 | #include
15 |
16 |
17 | pr_vertexbuffer* _pr_vertexbuffer_create()
18 | {
19 | pr_vertexbuffer* vertexBuffer = PR_MALLOC(pr_vertexbuffer);
20 |
21 | vertexBuffer->numVertices = 0;
22 | vertexBuffer->vertices = NULL;
23 |
24 | _pr_ref_add(vertexBuffer);
25 |
26 | return vertexBuffer;
27 | }
28 |
29 | void _pr_vertexbuffer_delete(pr_vertexbuffer* vertexBuffer)
30 | {
31 | if (vertexBuffer != NULL)
32 | {
33 | _pr_ref_release(vertexBuffer);
34 |
35 | PR_FREE(vertexBuffer->vertices);
36 | PR_FREE(vertexBuffer);
37 | }
38 | }
39 |
40 | void _pr_vertexbuffer_singular_init(pr_vertexbuffer* vertexBuffer, PRsizei numVertices)
41 | {
42 | if (vertexBuffer != NULL)
43 | {
44 | vertexBuffer->numVertices = numVertices;
45 | vertexBuffer->vertices = PR_CALLOC(pr_vertex, numVertices);
46 | }
47 | }
48 |
49 | void _pr_vertexbuffer_singular_clear(pr_vertexbuffer* vertexBuffer)
50 | {
51 | if (vertexBuffer != NULL)
52 | PR_FREE(vertexBuffer->vertices);
53 | }
54 |
55 | //!REMOVE THIS!
56 | static void _vertex_transform(
57 | pr_vertex* vertex, const pr_matrix4* worldViewProjectionMatrix, const pr_viewport* viewport)
58 | {
59 | // Transform view-space coordinate into projection space
60 | _pr_matrix_mul_float4(&(vertex->ndc.x), worldViewProjectionMatrix, &(vertex->coord.x));
61 |
62 | // Transform coordinate into normalized device coordinates
63 | vertex->ndc.z = 1.0f / vertex->ndc.w;
64 | vertex->ndc.x *= vertex->ndc.z;
65 | vertex->ndc.y *= vertex->ndc.z;
66 |
67 | // Transform vertex to screen coordiante (+0.5 is for rounding adjustment)
68 | vertex->ndc.x = viewport->x + (vertex->ndc.x + 1.0f) * viewport->halfWidth + 0.5f;
69 | vertex->ndc.y = viewport->y + (vertex->ndc.y + 1.0f) * viewport->halfHeight + 0.5f;
70 | //vertex->ndc.z = viewport->minDepth + vertex->ndc.z * viewport->depthSize;
71 |
72 | #ifdef PR_PERSPECTIVE_CORRECTED
73 | // Setup inverse-texture coordinates
74 | vertex->invTexCoord.x = vertex->texCoord.x * vertex->ndc.z;
75 | vertex->invTexCoord.y = vertex->texCoord.y * vertex->ndc.z;
76 | #endif
77 | }
78 |
79 | void _pr_vertexbuffer_transform(
80 | PRsizei numVertices, PRsizei firstVertex, pr_vertexbuffer* vertexBuffer,
81 | const pr_matrix4* worldViewProjectionMatrix, const pr_viewport* viewport)
82 | {
83 | const PRsizei lastVertex = numVertices + firstVertex;
84 |
85 | if (lastVertex >= vertexBuffer->numVertices)
86 | {
87 | _pr_error_set(PR_ERROR_INDEX_OUT_OF_BOUNDS, __FUNCTION__);
88 | return;
89 | }
90 |
91 | for (PRsizei i = firstVertex; i < lastVertex; ++i)
92 | _vertex_transform((vertexBuffer->vertices + i), worldViewProjectionMatrix, viewport);
93 | }
94 |
95 | void _pr_vertexbuffer_transform_all(
96 | pr_vertexbuffer* vertexBuffer, const pr_matrix4* worldViewProjectionMatrix, const pr_viewport* viewport)
97 | {
98 | for (PRsizei i = 0; i < vertexBuffer->numVertices; ++i)
99 | _vertex_transform((vertexBuffer->vertices + i), worldViewProjectionMatrix, viewport);
100 | }
101 |
102 | static void _vertexbuffer_resize(pr_vertexbuffer* vertexBuffer, PRsizei numVertices)
103 | {
104 | // Check if vertex buffer must be reallocated
105 | if (vertexBuffer->vertices == NULL || vertexBuffer->numVertices != numVertices)
106 | {
107 | // Create new vertex buffer data
108 | PR_FREE(vertexBuffer->vertices);
109 |
110 | vertexBuffer->numVertices = numVertices;
111 | vertexBuffer->vertices = PR_CALLOC(pr_vertex, numVertices);
112 | }
113 | }
114 |
115 | void _pr_vertexbuffer_data(pr_vertexbuffer* vertexBuffer, PRsizei numVertices, const PRvoid* coords, const PRvoid* texCoords, PRsizei vertexStride)
116 | {
117 | if (vertexBuffer == NULL)
118 | {
119 | PR_ERROR(PR_ERROR_NULL_POINTER);
120 | return;
121 | }
122 |
123 | _vertexbuffer_resize(vertexBuffer, numVertices);
124 |
125 | // Get offset pointers
126 | const PRbyte* coordsByteAlign = (const PRbyte*)coords;
127 | const PRbyte* texCoordsByteAlign = (const PRbyte*)texCoords;
128 |
129 | // Fill vertex buffer
130 | pr_vertex* vert = vertexBuffer->vertices;
131 |
132 | while (numVertices-- > 0)
133 | {
134 | // Copy coordinates
135 | if (coordsByteAlign != NULL)
136 | {
137 | const PRfloat* coord = (const PRfloat*)coordsByteAlign;
138 |
139 | vert->coord.x = coord[0];
140 | vert->coord.y = coord[1];
141 | vert->coord.z = coord[2];
142 | vert->coord.w = 1.0f;//coord[3];
143 |
144 | coordsByteAlign += vertexStride;
145 | }
146 | else
147 | {
148 | vert->coord.x = 0.0f;
149 | vert->coord.y = 0.0f;
150 | vert->coord.z = 0.0f;
151 | vert->coord.w = 1.0f;
152 | }
153 |
154 | // Copy texture coordinates
155 | if (texCoordsByteAlign != NULL)
156 | {
157 | const PRfloat* texCoord = (const PRfloat*)texCoordsByteAlign;
158 |
159 | vert->texCoord.x = texCoord[0];
160 | vert->texCoord.y = texCoord[1];
161 |
162 | texCoordsByteAlign += vertexStride;
163 | }
164 | else
165 | {
166 | vert->texCoord.x = 0.0f;
167 | vert->texCoord.y = 0.0f;
168 | }
169 |
170 | // Next vertex
171 | ++vert;
172 | }
173 | }
174 |
175 | void _pr_vertexbuffer_data_from_file(pr_vertexbuffer* vertexBuffer, PRsizei* numVertices, FILE* file)
176 | {
177 | if (vertexBuffer == NULL || numVertices == NULL || file == NULL)
178 | {
179 | PR_ERROR(PR_ERROR_NULL_POINTER);
180 | return;
181 | }
182 |
183 | // Read number of vertices
184 | PRushort vertCount = 0;
185 | fread(&vertCount, sizeof(PRushort), 1, file);
186 | *numVertices = (PRsizei)vertCount;
187 |
188 | _vertexbuffer_resize(vertexBuffer, *numVertices);
189 |
190 | // Read all vertices
191 | PRvertex data;
192 | pr_vertex* vert = vertexBuffer->vertices;
193 |
194 | for (PRushort i = 0; i < *numVertices; ++i)
195 | {
196 | if (feof(file))
197 | {
198 | PR_ERROR(PR_ERROR_UNEXPECTED_EOF);
199 | return;
200 | }
201 |
202 | // Read next vertex data
203 | fread(&data, sizeof(PRvertex), 1, file);
204 |
205 | vert->coord.x = data.x;
206 | vert->coord.y = data.y;
207 | vert->coord.z = data.z;
208 | vert->coord.w = 1.0f;
209 |
210 | vert->texCoord.x = data.u;
211 | vert->texCoord.y = data.v;
212 |
213 | ++vert;
214 | }
215 | }
216 |
217 |
--------------------------------------------------------------------------------
/src/rasterizer/vertexbuffer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vertexbuffer.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_VERTEXBUFFER_H
9 | #define PR_VERTEXBUFFER_H
10 |
11 |
12 | #include "vertex.h"
13 | #include "viewport.h"
14 | #include "structs.h"
15 |
16 | #include
17 |
18 |
19 | typedef struct pr_vertexbuffer
20 | {
21 | PRsizei numVertices;
22 | pr_vertex* vertices;
23 | }
24 | pr_vertexbuffer;
25 |
26 |
27 | pr_vertexbuffer* _pr_vertexbuffer_create();
28 | void _pr_vertexbuffer_delete(pr_vertexbuffer* vertexBuffer);
29 |
30 | void _pr_vertexbuffer_singular_init(pr_vertexbuffer* vertexBuffer, PRsizei numVertices);
31 | void _pr_vertexbuffer_singular_clear(pr_vertexbuffer* vertexBuffer);
32 |
33 | void _pr_vertexbuffer_transform(
34 | PRsizei numVertices,
35 | PRsizei firstVertex,
36 | pr_vertexbuffer* vertexBuffer,
37 | const pr_matrix4* worldViewProjectionMatrix,
38 | const pr_viewport* viewport
39 | );
40 |
41 | void _pr_vertexbuffer_transform_all(
42 | pr_vertexbuffer* vertexBuffer,
43 | const pr_matrix4* worldViewProjectionMatrix,
44 | const pr_viewport* viewport
45 | );
46 |
47 | void _pr_vertexbuffer_data(pr_vertexbuffer* vertexBuffer, PRsizei numVertices, const PRvoid* coords, const PRvoid* texCoords, PRsizei vertexStride);
48 | void _pr_vertexbuffer_data_from_file(pr_vertexbuffer* vertexBuffer, PRsizei* numVertices, FILE* file);
49 |
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/src/rasterizer/viewport.c:
--------------------------------------------------------------------------------
1 | /*
2 | * viewport.c
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include "viewport.h"
9 | #include "framebuffer.h"
10 | #include "error.h"
11 |
12 |
13 | void _pr_viewport_init(pr_viewport* viewport)
14 | {
15 | if (viewport != NULL)
16 | {
17 | viewport->x = 0.0f;
18 | viewport->y = 0.0f;
19 | viewport->halfWidth = 0.0f;
20 | viewport->halfHeight = 0.0f;
21 | viewport->minDepth = 0.0f;
22 | viewport->maxDepth = 1.0f;
23 | viewport->depthSize = 1.0f;
24 | }
25 | else
26 | _pr_error_set(PR_ERROR_NULL_POINTER, __FUNCTION__);
27 | }
28 |
--------------------------------------------------------------------------------
/src/rasterizer/viewport.h:
--------------------------------------------------------------------------------
1 | /*
2 | * viewport.h
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #ifndef PR_VIEWPORT_H
9 | #define PR_VIEWPORT_H
10 |
11 |
12 | #include "types.h"
13 |
14 |
15 | //! The viewport has only floats, becuase they will be
16 | //! used to transform the raster_vertex coordinates.
17 | typedef struct pr_viewport
18 | {
19 | PRfloat x;
20 | PRfloat y;
21 | PRfloat halfWidth;
22 | PRfloat halfHeight;
23 | PRfloat minDepth;
24 | PRfloat maxDepth;
25 | PRfloat depthSize; // (maxDepth - minDepth)
26 | }
27 | pr_viewport;
28 |
29 |
30 | void _pr_viewport_init(pr_viewport* viewport);
31 |
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/test/README.txt:
--------------------------------------------------------------------------------
1 |
2 | The CMake file will generate a test project for your OS (if supported).
3 | Set the working directory to this folder
4 | (e.g. "C:/Users/YourUserName/PicoRenderer/test/" on Windows,
5 | or "/home/YourUserName/PicoRenderer/test/" on a Posix system).
6 | Otherwise the resources from "test/media/" will not be loaded by the application.
7 |
--------------------------------------------------------------------------------
/test/SDL2/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * test.c (SDL2)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include
15 |
16 | #include
17 | #include
18 |
19 |
20 | // --- global members --- //
21 |
22 | SDL_Event event;
23 |
24 | PRobject context = NULL;
25 | PRobject frameBuffer = NULL;
26 | PRboolean isQuit = PR_FALSE;
27 |
28 | int mouseX = 0, mouseY = 0;
29 | int mouseSpeedX = 0, mouseSpeedY = 0;
30 | int mouseWheel = 0;
31 | int left = 0, right = 0, forward = 0, back = 0, faster = 0;
32 | bool buttonDown[2] = { 0 };
33 |
34 | bool keyDown[256] = { 0 };
35 |
36 | PRenum polyMode = PR_POLYGON_FILL;
37 |
38 | float pitch = 0.0f, yaw = 0.0f;
39 | float posZ = 3.0f;
40 |
41 | #define MOVE_CAMERA
42 | #ifdef MOVE_CAMERA
43 |
44 | #define MOVE_SPEED 0.02f
45 |
46 | float camX = 0.0f, camY = 0.0f, camZ = -20.0f;
47 |
48 | static void MoveCam(float x, float z)
49 | {
50 | float matrix[16];
51 | prLoadIdentity(matrix);
52 | prRotate(matrix, 0.0f, 1.0f, 0.0f, -yaw);
53 | prRotate(matrix, 1.0f, 0.0f, 0.0f, -pitch);
54 |
55 | float out[3];
56 | float in[3] = { x, 0.0f, z };
57 | _pr_matrix_mul_float3(out, (pr_matrix4*)matrix, in);
58 |
59 | float speed = MOVE_SPEED;
60 | if (faster)
61 | speed *= 5.0f;
62 |
63 | camX += out[0] * speed;
64 | camY += out[1] * speed;
65 | camZ += out[2] * speed;
66 | }
67 |
68 | #endif
69 |
70 | #define PI 3.141592654f
71 |
72 |
73 | // --- functions --- //
74 |
75 |
76 | void ErrorCallback(PRenum errorID, const char* info)
77 | {
78 | printf("PicoRenderer Error (%i): %s\n", errorID, info);
79 | }
80 |
81 | int main()
82 | {
83 |
84 | SDL_Init(SDL_INIT_EVERYTHING);
85 |
86 | #define SCREEN_MODE 1
87 | #if SCREEN_MODE == 1
88 | const PRuint screenWidth = 640;//800;
89 | const PRuint screenHeight = 480;//600;
90 | const PRboolean isFullscreen = PR_FALSE;
91 | #elif SCREEN_MODE == 2
92 | const PRuint screenWidth = 1280;
93 | const PRuint screenHeight = 768;
94 | const PRboolean isFullscreen = PR_TRUE;
95 | #elif SCREEN_MODE == 3
96 | const PRuint screenWidth = 1600;
97 | const PRuint screenHeight = 900;
98 | const PRboolean isFullscreen = PR_FALSE;
99 | #else
100 | const PRuint screenWidth = 1920;
101 | const PRuint screenHeight = 1080;
102 | const PRboolean isFullscreen = PR_TRUE;
103 | #endif
104 |
105 | // Initialize renderer
106 | prInit();
107 | prErrorHandler(ErrorCallback);
108 |
109 | printf("%s %s\n", prGetString(PR_STRING_RENDERER), prGetString(PR_STRING_VERSION));
110 |
111 | // Create render context
112 | PRcontextdesc contextDesc;
113 |
114 | contextDesc.window = (void *)SDL_CreateWindow("pico_renderer_test(SDL2)", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screenWidth, screenHeight, SDL_WINDOW_SHOWN);
115 |
116 | context = prCreateContext(&contextDesc, screenWidth, screenHeight);
117 |
118 | // Create frame buffer
119 | frameBuffer = prCreateFrameBuffer(screenWidth, screenHeight);
120 | prBindFrameBuffer(frameBuffer);
121 |
122 | // Create textures
123 | #ifdef PR_COLOR_BUFFER_24BIT
124 | const PRboolean dither = PR_FALSE;
125 | #else
126 | const PRboolean dither = PR_TRUE;
127 | #endif
128 |
129 | PRobject textureA = prCreateTexture();
130 | prTexImage2DFromFile(textureA, "media/house.jpg", dither, PR_TRUE); //TODO change it back to "media/house.jpg"
131 |
132 | PRobject textureB = prCreateTexture();
133 | prTexImage2DFromFile(textureB, "media/tiles.png", dither, PR_TRUE);
134 |
135 | //prTexEnvi(PR_TEXTURE_LOD_BIAS, 1);
136 |
137 | // Create vertex buffer
138 | PRobject vertexBuffer = prCreateVertexBuffer();
139 | PRobject indexBuffer = prCreateIndexBuffer();
140 |
141 | #if 0
142 |
143 | #define NUM_VERTICES 24
144 |
145 | PRvertex cubeVertices[NUM_VERTICES] =
146 | {
147 | // x y z u v
148 | // front
149 | { -1.0f, 1.0f, -1.0f, 0.0f, 0.0f },
150 | { 1.0f, 1.0f, -1.0f, 1.0f, 0.0f },
151 | { 1.0f, -1.0f, -1.0f, 1.0f, 1.0f },
152 | { -1.0f, -1.0f, -1.0f, 0.0f, 1.0f },
153 |
154 | // back
155 | { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f },
156 | { -1.0f, 1.0f, 1.0f, 1.0f, 0.0f },
157 | { -1.0f, -1.0f, 1.0f, 1.0f, 1.0f },
158 | { 1.0f, -1.0f, 1.0f, 0.0f, 1.0f },
159 |
160 | // left
161 | { -1.0f, 1.0f, 1.0f, 0.0f, 0.0f },
162 | { -1.0f, 1.0f, -1.0f, 1.0f, 0.0f },
163 | { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f },
164 | { -1.0f, -1.0f, 1.0f, 0.0f, 1.0f },
165 |
166 | // right
167 | { 1.0f, 1.0f, -1.0f, 0.0f, 0.0f },
168 | { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f },
169 | { 1.0f, -1.0f, 1.0f, 1.0f, 1.0f },
170 | { 1.0f, -1.0f, -1.0f, 0.0f, 1.0f },
171 |
172 | // top
173 | { -1.0f, 1.0f, 1.0f, 0.0f, 0.0f },
174 | { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f },
175 | { 1.0f, 1.0f, -1.0f, 1.0f, 1.0f },
176 | { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f },
177 |
178 | // bottom
179 | { -1.0f, -1.0f, -1.0f, 0.0f, 0.0f },
180 | { 1.0f, -1.0f, -1.0f, 1.0f, 0.0f },
181 | { 1.0f, -1.0f, 1.0f, 1.0f, 1.0f },
182 | { -1.0f, -1.0f, 1.0f, 0.0f, 1.0f }
183 | };
184 | prVertexBufferData(vertexBuffer, NUM_VERTICES, &(cubeVertices[0].x), &(cubeVertices[0].u), sizeof(PRvertex));
185 |
186 | #define NUM_INDICES 36
187 |
188 | PRushort cubeIndices[NUM_INDICES] =
189 | {
190 | 0, 1, 2, 0, 2, 3, // front
191 | 4, 5, 6, 4, 6, 7, // back
192 | 8, 9,10, 8,10,11, // left
193 | 12,13,14, 12,14,15, // right
194 | 16,17,18, 16,18,19, // top
195 | 20,21,22, 20,22,23, // bottom
196 | };
197 | prIndexBufferData(indexBuffer, cubeIndices, NUM_INDICES);
198 |
199 | //float size[3] = { 2.0f, 2.0f, 0.5f };
200 | float size[3] = { 1.0f, 1.0f, 1.0f };
201 |
202 | #else
203 |
204 | #define NUM_VERTICES numVertices
205 | #define NUM_INDICES numIndices
206 |
207 | PRsizei numVertices = 0, numIndices = 0;
208 |
209 | FILE* mdlFile = fopen("media/house_tris.pico", "rb");
210 | if (mdlFile)
211 | {
212 | prVertexBufferDataFromFile(vertexBuffer, &numVertices, mdlFile);
213 | prIndexBufferDataFromFile(indexBuffer, &numIndices, mdlFile);
214 | fclose(mdlFile);
215 | }
216 | else
217 | puts("could not open model file!");
218 |
219 | float size[3] = { 5, -5, 5 };//0.7f, -0.7f, 0.7f };
220 |
221 | #endif
222 |
223 | // Setup matrices
224 | float projectionA[16], projectionB[16], worldMatrix[16], viewMatrix[16];
225 |
226 | #if 0
227 | PRuint viewWidth = 200;
228 | PRuint viewHeight = 200;
229 | #else
230 | PRuint viewWidth = screenWidth;
231 | PRuint viewHeight = screenHeight;
232 | #endif
233 |
234 | float orthoSize = 0.007f;//0.02f;
235 | prBuildPerspectiveProjection(projectionA, (float)viewWidth/viewHeight, 0.01f, 100.0f, 74.0f * PR_DEG2RAD);
236 | prBuildOrthogonalProjection(projectionB, orthoSize*viewWidth, orthoSize*viewHeight, 0.1f, 100.0f);
237 |
238 | prLoadIdentity(viewMatrix);
239 | prViewMatrix(viewMatrix);
240 |
241 | //prCullMode(PR_CULL_BACK);
242 | prCullMode(PR_CULL_FRONT);
243 |
244 | clock_t startTime = clock();
245 | int fps = 0;
246 |
247 | prEnable(PR_MIP_MAPPING);
248 |
249 | // Main loop
250 | while (!isQuit)
251 | {
252 | // Reset input states
253 |
254 | SDL_GetMouseState(&mouseX, &mouseY);
255 |
256 | mouseSpeedX = (mouseX - (screenWidth/2));
257 | mouseSpeedY = (mouseY - (screenHeight/2));
258 | mouseWheel = 0;
259 |
260 |
261 |
262 | // Window event handling
263 |
264 | while (SDL_PollEvent(&event) != 0)
265 | {
266 | // Update user input
267 |
268 | if(event.type == SDL_QUIT)
269 | isQuit = 1;
270 |
271 | switch(event.type)
272 | {
273 | case SDL_MOUSEBUTTONDOWN:
274 | SDL_GetMouseState(&mouseX, &mouseY);
275 | yaw -= PI*0.0025f*(float)abs((mouseSpeedX - (screenWidth/2)) - (mouseX - (screenWidth/2)));//event.button.y
276 | pitch += PI*0.0025f*(float)abs((mouseSpeedY - (screenHeight/2)) - (mouseY - (screenHeight/2)));
277 | break;
278 | case SDL_MOUSEBUTTONUP:
279 |
280 | break;
281 | case SDL_MOUSEWHEEL:
282 | posZ += 0.1f * event.wheel.y;
283 | break;
284 | }
285 |
286 |
287 |
288 |
289 | #ifdef MOVE_CAMERA
290 |
291 | if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_RIGHT)
292 | yaw -= PI*0.0025f*(float)6.5;
293 | if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_LEFT)
294 | yaw += PI*0.0025f*(float)6.5;
295 | if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_UP)
296 | pitch += PI*0.0025f*(float)6.5;
297 | if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_DOWN)
298 | pitch -= PI*0.0025f*(float)6.5;
299 |
300 |
301 |
302 |
303 | if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_w)
304 | forward = 1;
305 | if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_s)
306 | back = 1;
307 | if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_a)
308 | left = 1;
309 | if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_d)
310 | right = 1;
311 | if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_w)
312 | forward = 0;
313 | if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_s)
314 | back = 0;
315 | if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_a)
316 | left = 0;
317 | if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_d)
318 | right = 0;
319 | if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_LSHIFT)
320 | faster = 1;
321 | if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_LSHIFT)
322 | faster = 0;
323 |
324 | #endif
325 | }
326 |
327 | if (pitch < -PI*0.5f)
328 | pitch = -PI*0.5f;
329 | if (pitch > PI*0.5f)
330 | pitch = PI*0.5f;
331 |
332 | prLoadIdentity(viewMatrix);
333 | prRotate(viewMatrix, 1.0f, 0.0f, 0.0f, pitch);
334 | prRotate(viewMatrix, 0.0f, 1.0f, 0.0f, yaw);
335 | prRotate(viewMatrix, 0.0f, 0.0f, 1.0f, 180.0f * PR_DEG2RAD);
336 | prTranslate(viewMatrix, camX, camY, -camZ);
337 | prViewMatrix(viewMatrix);
338 |
339 | if(forward)
340 | MoveCam(0, 1);
341 | if(back)
342 | MoveCam(0, -1);
343 | if(left)
344 | MoveCam(-1, 0);
345 | if(right)
346 | MoveCam(1, 0);
347 |
348 | #if 0
349 | // Show FPS
350 | ++fps;
351 | if (clock()/CLOCKS_PER_SEC > startTime/CLOCKS_PER_SEC)
352 | {
353 | startTime = clock();
354 | printf("fps = %i\n", fps);
355 | fps = 0;
356 | }
357 | #endif
358 |
359 |
360 |
361 | // Drawing
362 | prClearColor(255, 255, 255);
363 | prClearFrameBuffer(frameBuffer, 0.0f, PR_COLOR_BUFFER_BIT | PR_DEPTH_BUFFER_BIT);
364 | {
365 | #if 0
366 |
367 | prDrawScreenLine(300, 200, 500, 200, prGetColorIndex(255, 0, 0));
368 | prDrawScreenLine(500, 200, 500, 400, prGetColorIndex(0, 255, 0));
369 | prDrawScreenLine(500, 400, 300, 400, prGetColorIndex(0, 0, 255));
370 | prDrawScreenLine(300, 400, 300, 200, prGetColorIndex(0, 255, 255));
371 |
372 | prDrawScreenLine(10, 10, mouseX, mouseY, prGetColorIndex(255, 255, 0));
373 |
374 | #elif 0
375 |
376 | for (int y = 0; y < 256; ++y)
377 | prDrawScreenLine(100, 100 + y, 356, 100 + y, prGetColorIndex(y, y, y));
378 |
379 | #elif 0
380 |
381 | prColor(prGetColorIndex(255, 0, 0));
382 | prBindTexture(textureA);
383 |
384 | prDrawScreenImage(100, 100, mouseX, mouseY);
385 |
386 | #elif 0
387 |
388 | // Bind buffers
389 | prBindVertexBuffer(vertexBuffer);
390 | prBindIndexBuffer(indexBuffer);
391 |
392 | // Setup view
393 | prViewport(0, 0, viewWidth, viewHeight);
394 | prColor(0, 0, 255);
395 |
396 | // Setup transformation
397 | prProjectionMatrix(projectionB);
398 | prLoadIdentity(worldMatrix);
399 | #ifndef viewMatrix
400 | prTranslate(worldMatrix, 0.0f, 0.0f, posZ);
401 | prRotate(worldMatrix, 1.0f, 0.0f, 0.0f, pitch);
402 | prRotate(worldMatrix, 0.0f, 1.0f, 0.0f, -yaw);
403 | #endif
404 | prScale(worldMatrix, size[0], size[1], size[2]);
405 | prWorldMatrix(worldMatrix);
406 |
407 | // Draw lines
408 | prDrawIndexed(PR_LINES, NUM_INDICES, 0);
409 |
410 | // Setup view
411 | prViewport(viewWidth, 0, 600, 600);
412 | prColor(255, 0, 0);
413 |
414 | // Setup transformation
415 | prProjectionMatrix(projectionA);
416 | prLoadIdentity(worldMatrix);
417 | prTranslate(worldMatrix, 0.0f, 0.0f, posZ);
418 | prRotate(worldMatrix, 1.0f, 0.0f, 0.0f, pitch);
419 | prRotate(worldMatrix, 0.0f, 1.0f, 0.0f, yaw);
420 | prScale(worldMatrix, size[0], size[1], size[2]);
421 | prWorldMatrix(worldMatrix);
422 |
423 | // Draw lines
424 | prDrawIndexed(PR_LINES, NUM_INDICES, 0);
425 |
426 | #elif 1
427 |
428 | prColor(0, 0, 255);
429 |
430 | // Bind buffers
431 | prBindVertexBuffer(vertexBuffer);
432 | prBindIndexBuffer(indexBuffer);
433 | prBindTexture(textureA);
434 |
435 | // Setup view
436 | prViewport(0, 0, viewWidth, viewHeight);
437 |
438 | //prEnable(PR_SCISSOR);
439 | //prScissor(20, 20, viewWidth - 100, viewHeight - 100);
440 |
441 | prPolygonMode(polyMode);
442 |
443 | // Setup transformation
444 | prProjectionMatrix(projectionA);
445 | prLoadIdentity(worldMatrix);
446 | #ifndef MOVE_CAMERA
447 | prTranslate(worldMatrix, 0.0f, 0.0f, posZ);
448 | prRotate(worldMatrix, 1.0f, 0.0f, 0.0f, pitch);
449 | prRotate(worldMatrix, 0.0f, 1.0f, 0.0f, yaw);
450 | #endif
451 | prScale(worldMatrix, size[0], size[1], size[2]);
452 | prWorldMatrix(worldMatrix);
453 |
454 | // Draw triangles
455 | //prDepthRange(0.0f, 0.5f);
456 | prDrawIndexed(PR_TRIANGLES, NUM_INDICES, 0);
457 |
458 | #if 1
459 | for (int i = 1; i < 9; ++i)
460 | {
461 | worldMatrix[12] = ((float)(i % 3))*5*size[0];
462 | worldMatrix[14] = ((float)(i / 3))*5*size[2];
463 | prWorldMatrix(worldMatrix);
464 | prDrawIndexed(PR_TRIANGLES, NUM_INDICES, 0);
465 | }
466 | #endif
467 |
468 | // Draw floor
469 | float floorSize = 100.0f;
470 | int numQuads = 50;
471 |
472 | prLoadIdentity(worldMatrix);
473 | prTranslate(worldMatrix, 0, 4, 0);
474 | prScale(worldMatrix, floorSize, floorSize, floorSize);
475 | prWorldMatrix(worldMatrix);
476 |
477 | prBindTexture(textureB);
478 |
479 | prBegin(PR_TRIANGLES);
480 | {
481 | #if defined(PR_PERSPECTIVE_CORRECTED) && 0
482 |
483 | // Only use a single quad when textures are perspective corrected
484 | prTexCoord2i(0, 0); prVertex3f(-1, 0, 1);
485 | prTexCoord2i(numQuads, 0); prVertex3f(1, 0, 1);
486 | prTexCoord2i(numQuads, numQuads); prVertex3f(1, 0, -1);
487 |
488 | prTexCoord2i(0, 0); prVertex3f(-1, 0, 1);
489 | prTexCoord2i(numQuads, numQuads); prVertex3f(1, 0, -1);
490 | prTexCoord2i(0, numQuads); prVertex3f(-1, 0, -1);
491 |
492 | #else
493 |
494 | // Use many quads to emulate perspective texture correction
495 | float step = 2.0f / (float)numQuads;
496 |
497 | for (float x = -1.0f; x < 1.0f; x += step)
498 | {
499 | for (float z = -1.0f; z < 1.0f; z += step)
500 | {
501 | prTexCoord2i(0, 0); prVertex3f(x, 0, z + step);
502 | prTexCoord2i(1, 0); prVertex3f(x + step, 0, z + step);
503 | prTexCoord2i(1, 1); prVertex3f(x + step, 0, z);
504 |
505 | prTexCoord2i(0, 0); prVertex3f(x, 0, z + step);
506 | prTexCoord2i(1, 1); prVertex3f(x + step, 0, z);
507 | prTexCoord2i(0, 1); prVertex3f(x, 0, z);
508 | }
509 | }
510 |
511 | #endif
512 | }
513 | prEnd();
514 |
515 | # if 0
516 |
517 | // Draw with immediate mode
518 | prBindTexture(0);
519 | prColor(255, 0, 0);
520 |
521 | static float angle;
522 |
523 | //angle += 0.02f;
524 | if (buttonDown[1])
525 | angle += 0.02f * mouseSpeedX;
526 |
527 | prLoadIdentity(worldMatrix);
528 | prProjectionMatrix(worldMatrix);
529 | #ifndef MOVE_CAMERA
530 | prTranslate(worldMatrix, 0, 0, 1.5f);
531 | prRotate(worldMatrix, 0, 0, 1, angle);
532 | #endif
533 | prScale(worldMatrix, 0.7f, 0.7f, 0.7f);
534 | prWorldMatrix(worldMatrix);
535 |
536 | prCullMode(PR_CULL_NONE);
537 | prPolygonMode(PR_POLYGON_FILL);
538 | prDisable(PR_SCISSOR);
539 |
540 | prViewport(0, 0, 100, 100);
541 |
542 | prBegin(PR_TRIANGLES);
543 | {
544 | prVertex2f(0, 1.155f);
545 | prVertex2f(1, -0.577f);
546 | prVertex2f(-1, -0.577f);
547 | }
548 | prEnd();
549 |
550 | # endif
551 |
552 | # if 0
553 | // Setup transformation
554 | prLoadIdentity(worldMatrix);
555 | #ifndef MOVE_CAMERA
556 | prTranslate(worldMatrix, 1.5f, 0.0f, posZ);
557 | prRotate(worldMatrix, 1.0f, 1.0f, 1.0f, pitch);
558 | #endif
559 | prWorldMatrix(worldMatrix);
560 |
561 | prBindTexture(textureB);
562 |
563 | // Draw triangles
564 | //prDepthRange(0.5f, 1.0f);
565 | prDrawIndexed(PR_TRIANGLES, NUM_INDICES, 0);
566 | # endif
567 |
568 | #endif
569 | }
570 | prPresent(context);
571 | }
572 |
573 | // Clean up
574 | prDeleteTexture(textureA);
575 | prDeleteTexture(textureB);
576 | prDeleteVertexBuffer(vertexBuffer);
577 | prDeleteIndexBuffer(indexBuffer);
578 | prDeleteFrameBuffer(frameBuffer);
579 | prDeleteContext(context);
580 |
581 | prRelease();
582 |
583 | SDL_Quit();
584 |
585 | return 0;
586 | }
587 |
--------------------------------------------------------------------------------
/test/linux/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * test.c (Linux)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | // --- global members --- //
13 |
14 | PRuint scrWidth = 640;
15 | PRuint scrHeight = 480;
16 |
17 |
18 | // --- functions --- //
19 |
20 | int main()
21 | {
22 | // Open connection to X11 server
23 | Display* display = XOpenDisplay(NULL);
24 |
25 | if (!display)
26 | {
27 | fprintf(stderr, "Opening X11 display failed\n");
28 | return 1;
29 | }
30 |
31 | // Get default resources
32 | int screen = DefaultScreen(display);
33 | Visual* visual = DefaultVisual(display, screen);
34 | int depth = DefaultDepth(display, screen);
35 | Window rootWnd = RootWindow(display, screen);
36 |
37 | int displayWidth = DisplayWidth(display, screen);
38 | int displayHeight = DisplayHeight(display, screen);
39 |
40 | unsigned long whitePixel = WhitePixel(display, screen);
41 | unsigned long blackPixel = BlackPixel(display, screen);
42 |
43 | XSetWindowAttributes attribs;
44 | attribs.background_pixel = whitePixel;
45 |
46 | #if 1//DEBUG
47 | printf("DefaultScreen = %i\n", screen);
48 | printf("DisplaySize = (%i, %i)\n", displayWidth, displayHeight);
49 | printf("RootWindow = %lu\n", rootWnd);
50 | printf("WhitePixel = %lu\nBlackPixel = %lu\n", whitePixel, blackPixel);
51 | #endif
52 |
53 | // Create window
54 | unsigned int borderWidth = 5;
55 |
56 | int wndWidth = (int)scrWidth;
57 | int wndHeight = (int)scrHeight;
58 |
59 | Window wnd = XCreateWindow(
60 | display,
61 | rootWnd,
62 | displayWidth/2 - wndWidth/2,
63 | displayHeight/2 - wndHeight/2,
64 | wndWidth,
65 | wndHeight,
66 | borderWidth,
67 | depth,
68 | InputOutput,
69 | visual,
70 | CWBackPixel,
71 | &attribs
72 | );
73 |
74 | printf("wnd = %lu\n", wnd);
75 |
76 | //XMapRaised(display, wnd);
77 | XStoreName(display, wnd, "pico_renderer test (Linux)");
78 | XSelectInput(display, wnd, ExposureMask | KeyPressMask);
79 | XMapWindow(display, wnd);
80 |
81 | // Create graphics context
82 | //GC gfx = XCreateGC(display, wnd, GCFont + GCForeground);
83 |
84 |
85 | // Initialize pico renderer
86 | prInit();
87 |
88 | // Create graphics context
89 | PRcontextdesc contextDesc;
90 | contextDesc.window = (void*)(&wnd);
91 | PRobject context = prCreateContext(&contextDesc, scrWidth, scrHeight);
92 |
93 | if (context == NULL)
94 | {
95 | fprintf(stderr, "pico_renderer: context creation failed!\n");
96 | return 0;
97 | }
98 |
99 | // Main loop
100 | XEvent event;
101 |
102 | PRboolean isQuit = PR_FALSE;
103 |
104 | while (!isQuit)
105 | {
106 | // Update window event
107 | XNextEvent(display, &event);
108 |
109 | switch (event.type)
110 | {
111 | case KeyPress:
112 | {
113 | switch (event.xkey.keycode)
114 | {
115 | case 9: // ESC
116 | isQuit = PR_TRUE;
117 | break;
118 | }
119 | printf("Key Pressed: %i\n", event.xkey.keycode);
120 | }
121 | break;
122 | }
123 |
124 | // Draw scene
125 | //todo...
126 | }
127 |
128 | // Clean up
129 | XCloseDisplay(display);
130 |
131 | prRelease();
132 |
133 | return 0;
134 | }
135 |
136 |
--------------------------------------------------------------------------------
/test/macos/main.m:
--------------------------------------------------------------------------------
1 | /*
2 | * test.c (MacOS)
3 | *
4 | * This file is part of the "PicoRenderer" (Copyright (c) 2014 by Lukas Hermanns)
5 | * See "LICENSE.txt" for license information.
6 | */
7 |
8 | #import
9 |
10 | #include
11 | #include
12 |
13 |
14 | // --- global members --- //
15 |
16 | PRobject context = NULL;
17 | PRobject frameBuffer = NULL;
18 | PRboolean isQuit = PR_FALSE;
19 |
20 | PRuint scrWidth = 640;
21 | PRuint scrHeight = 480;
22 |
23 |
24 | // --- interfaces --- //
25 |
26 | @interface AppDelegate : NSObject
27 | {
28 | BOOL _quit;
29 | }
30 | - (id) initApp;
31 | - (BOOL) isQuit;
32 | @end
33 |
34 | @implementation AppDelegate
35 |
36 | - (id) initApp
37 | {
38 | self = [super init];
39 | _quit = FALSE;
40 | return (self);
41 | }
42 |
43 | - (void) windowWillClose:(id)sender
44 | {
45 | _quit = TRUE;
46 | }
47 |
48 | - (BOOL) isQuit
49 | {
50 | return (_quit);
51 | }
52 |
53 |
54 | @end
55 |
56 |
57 | // --- functions --- //
58 |
59 | static void postKeyEvent(void* event)
60 | {
61 | NSString* s = [(NSEvent*)event characters];
62 |
63 | if (s != nil && [s length] > 0)
64 | {
65 | unsigned int c = [s characterAtIndex:0];
66 |
67 | switch (c)
68 | {
69 | case 27: // ESC
70 | isQuit = PR_TRUE;
71 | break;
72 | }
73 | }
74 |
75 | [s release];
76 | }
77 |
78 | static void processEvents(NSWindow* wnd)
79 | {
80 | for (;;)
81 | {
82 | NSEvent* event = [wnd
83 | nextEventMatchingMask: NSEventMaskAny
84 | untilDate: nil
85 | inMode: NSDefaultRunLoopMode
86 | dequeue: YES
87 | ];
88 |
89 | if (event == nil)
90 | break;
91 |
92 | switch ([event type])
93 | {
94 | case NSEventTypeKeyDown:
95 | postKeyEvent(event);
96 | break;
97 |
98 | default:
99 | [NSApp sendEvent:event];
100 | break;
101 | }
102 | }
103 | }
104 |
105 | int main(int argc, char* argv[])
106 | {
107 | // Create window with cocoa framework
108 | [[NSAutoreleasePool alloc] init];
109 | [NSApplication sharedApplication];
110 | [NSApp setDelegate:(id)[[[AppDelegate alloc] initApp] autorelease]];
111 | //[NSBundle loadNibNamed:@"MainMenu" owner:[NSApp delegate]];
112 | [NSApp finishLaunching];
113 |
114 | NSWindow* window = NULL;
115 |
116 | window = [[NSWindow alloc]
117 | initWithContentRect: NSMakeRect(0, 0, (CGFloat)scrWidth, (CGFloat)scrHeight)
118 | styleMask: (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable)
119 | backing: NSBackingStoreBuffered
120 | defer: NO
121 | ];
122 |
123 | [window center];
124 | [window setDelegate:(id)[NSApp delegate]];
125 | [window setAcceptsMouseMovedEvents:YES];
126 | [window setIsVisible:YES];
127 | [window makeKeyAndOrderFront:nil];
128 | [window setTitle:@"pico_renderer test (MacOS)"];
129 |
130 | // Initialize renderer
131 | prInit();
132 |
133 | // Create graphics context
134 | PRcontextdesc contextDesc;
135 | contextDesc.window = (void*)window;
136 | PRobject context = prCreateContext(&contextDesc, scrWidth, scrHeight);
137 | //prMakeCurrent();
138 |
139 | // Create frame buffer
140 | frameBuffer = prCreateFrameBuffer(scrWidth, scrHeight);
141 | prBindFrameBuffer(frameBuffer);
142 |
143 | prClearColor(0, 0, 0);
144 |
145 | // Setup projection matrix
146 | PRfloat projection[16];
147 | prBuildPerspectiveProjection(
148 | projection, // output matrix
149 | (PRfloat)scrWidth/scrHeight, // aspect ratio
150 | 1.0f, // near clipping plane
151 | 100.0f, // far clipping plane
152 | 74.0f * PR_DEG2RAD // field of view (fov) in radians
153 | );
154 | prProjectionMatrix(projection);
155 |
156 | // World transform
157 | PRfloat worldMatrix[16];
158 | PRfloat rotation = 0.0f;
159 |
160 | PRobject tex0 = prCreateTexture();
161 | prTexImage2DFromFile(tex0, "crate.png", PR_TRUE, PR_TRUE);
162 | prTexEnvi(PR_TEXTURE_LOD_BIAS, 2);
163 |
164 | // Main loop
165 | while (!isQuit)
166 | {
167 | // Process events
168 | processEvents(window);
169 |
170 | if ([(AppDelegate*)[NSApp delegate] isQuit])
171 | isQuit = PR_TRUE;
172 |
173 | // Setup viewport
174 | prViewport(0, 0, scrWidth, scrHeight);
175 |
176 | // Setup world matrix
177 | prLoadIdentity(worldMatrix);
178 | prTranslate(worldMatrix, 0, 0, 4);
179 | prRotate(worldMatrix, 1, 0, 0, M_PI*0.28);
180 | prRotate(worldMatrix, 0, 0, 1, rotation);
181 | prScale(worldMatrix, 2, 2, 2);
182 | prWorldMatrix(worldMatrix);
183 | rotation += 0.01f;//0.025f;
184 |
185 | // Draw scene
186 | prClearFrameBuffer(
187 | frameBuffer,
188 | 0.0f,
189 | PR_COLOR_BUFFER_BIT | PR_DEPTH_BUFFER_BIT
190 | );
191 |
192 | prColor(255, 255, 0);
193 |
194 | prBindTexture(tex0);
195 | prBegin(PR_TRIANGLES);
196 | {
197 | prTexCoord2i(0, 0);
198 | prVertex2i(-1, 1);
199 |
200 | prTexCoord2f(1, 0);
201 | prVertex2i(1, 1);
202 |
203 | prTexCoord2i(1, 1);
204 | prVertex2i(1, -1);
205 |
206 | prTexCoord2i(0, 0);
207 | prVertex2i(-1, 1);
208 |
209 | prTexCoord2i(1, 1);
210 | prVertex2i(1, -1);
211 |
212 | prTexCoord2f(0, 1);
213 | prVertex2i(-1, -1);
214 | }
215 | prEnd();
216 |
217 | prPresent(context);
218 | }
219 |
220 | // Clean up
221 | prDeleteFrameBuffer(frameBuffer);
222 | prDeleteContext(context);
223 |
224 | prRelease();
225 |
226 | return 0;
227 | }
228 |
229 |
--------------------------------------------------------------------------------
/test/media/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/banner.png
--------------------------------------------------------------------------------
/test/media/crate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/crate.png
--------------------------------------------------------------------------------
/test/media/front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/front.png
--------------------------------------------------------------------------------
/test/media/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/grid.png
--------------------------------------------------------------------------------
/test/media/house.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/house.jpg
--------------------------------------------------------------------------------
/test/media/house_lines.pico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/house_lines.pico
--------------------------------------------------------------------------------
/test/media/house_tris.pico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/house_tris.pico
--------------------------------------------------------------------------------
/test/media/npot_tex_127.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/npot_tex_127.png
--------------------------------------------------------------------------------
/test/media/npot_tex_129.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/npot_tex_129.png
--------------------------------------------------------------------------------
/test/media/palette1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/palette1.png
--------------------------------------------------------------------------------
/test/media/preview_macos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/preview_macos.png
--------------------------------------------------------------------------------
/test/media/preview_win32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/preview_win32.png
--------------------------------------------------------------------------------
/test/media/tiles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LukasBanana/PicoRenderer/e433fefe91b0caa5833af7c370956ccf03bbf5f2/test/media/tiles.png
--------------------------------------------------------------------------------