├── .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 |

test/media/preview_win32.png

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 --------------------------------------------------------------------------------